Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

francois's avatar

eager loading and PHP (not MYSQL) performance issue

Hello,

I was optimizing an app, where I need to export some data.

There is a query to export around 12 000 rows, but for all rows, there is 3 or 4 relations used.

When I execute the request excluding the relations data, export is build in less than 0.5s. But, when I add this relations (with eager loading, or not) in the export, request take more than 2 min.

I've looked at the server side, and mysql is not really overloaded, but apache is used at 100% on one thread during those 2 mins.

So, I think it's a php/Eloquent issue, and not from the request.

My question is : If a relations is declared in my php application (the Eloquent way), but I have not set the foreign key on the mysql side, may it generate performance issue for Eloquent, where Eloquent needs to test if the relation is set on active record etc ? Because I know I can use indexes, but we work on around 50 000 rows in our tables, so in can't explain this time difference.

Thanks

0 likes
14 replies
pmall's avatar
pmall
Best Answer
Level 56

Create indexes for your foreign keys. Even for 50 000 rows.

If you load 12 000 eloquent object + 4 relationship for each in memory there will be problems. Use the chunk method to treat them by smaller chunks.

francois's avatar

There is more than 10Go free RAM during process, so I don't think it's a memory issue. CPU is overloaded on the apache process.

Do you really think the foreign keys will have significant impact on request execution ?

I don't really understand how I can use chunk on my request, do you have more explicit example ?

pmall's avatar

Trust me processing 12 000 eloquent object cant work.

I guess they are processed in a loop so instead of selecting them all at once you can slice it in smaller chunks :

YourModel::with('your.relationships')->chunk(100, function($your_models)
{
    foreach ($your_models as $your_model)
    {
        process($your_model);
    }
});

With the above they are processed 100 by 100

francois's avatar

I've updated this :

public function buildCsv($outputName, $data)
    {

        foreach($data as $row)
        {
            $this->insertRow($row);
        }

        return $this->csvManager->output($outputName . '.csv');
    }

to

public function buildCsv($outputName, $data)
    {

        $data->chunk(100, function($rows)
        {
            foreach ($rows as $row)
            {
                $this->insertRow($row);
            }
        });

        return $this->csvManager->output($outputName . '.csv');
    }

Where $data is always the result of the eloquent query.

But, after these 2 mins (and only after) I got :

production.ERROR: exception 'ErrorException' with message 'array_chunk() expects parameter 3 to be boolean, object given'

ps : The fact that the error is just displaying after 2 min seems to approve an eloquent/php issue or I'm again on the wrong way ? Because if the chunk is executed after 2 min, it means that it's not the biggest part of the request.

rikh's avatar

If you can't identify exactly where the performance hit is coming from, then I would suggest stepping through the code in the debugger. When you hit a step that is taking a long time to complete, run it again and step into that function until you zero on the thing that is actually taking all your time.

If you have a profiler, this will do the hard work for you and identify exactly where all your performance is going. It is often something silly that is easy to avoid :-)

pmall's avatar

Where $data is always the result of the eloquent query.

The problem is on the data selection. You have to use chunk to select the data. instead of get(). Here you are using the chunk method of the already selected collection.

francois's avatar

Exactly, I was testing this.

This reduce request time execution to 1 min. It's always too much but 50% save is really great. Thanks

pmall's avatar

Still 1 min ?? Did you put indexes on foreign keys ?

francois's avatar

I'm preparing a migration to test this in production. I have to update all my repositories to include this chunk method when I need it. I'll give a feed back when all of this will deployed.

francois's avatar

So, after deploying code with indexes (migrations) and chunk, I've still won 50% time. So with or without indexes, it's 1min.

johanobergman's avatar

Do you really have to use Eloquent? You would get a lot better performance if you stick with the regular query builder (like 10-30+ times faster depending on the size of the collection).

francois's avatar

Sure, it's a solution, but I don't thinks it's the easiest to maintain.

pmall's avatar

Indexes should have speed up your queries, are you sure you are creating good indexes?

francois's avatar

Yes, really sure.

As I've already mentioned, mysql is not so much used. On another export, where I don't need to use Eloquent relations, the export on the same counted rows is done in less than 1s.

I'm on Apache2.2 and I think it's a part of my performance issue. The point is that Mysql isn't loaded so I really think it's an Eloquent issue.

I think I should dump the query to see time execution when I run it directly in Mysql.

Please or to participate in this conversation.