Why Laravel Is Slow
Slow Code series
- Eloquent Abused By Many Developers (2016-11-08)
- Why Laravel Is Slow - Eager Loading, Caching (2016-11-05)
- Why Laravel Is Slow (2016-11-04)
I bump into this question time to time when browsing the web or talking to fellow developers. It is something that you cannot answer with a simple “well because of that!”. Sometimes it is like telling your child that how babies are made, how life works, etc.
They just simply wouldn’t accept the truth at first glance.
And what is the hidden truth behind this “Laravel is slow” concept?
It is fairly easy: Your code is slow.
1st Common mistake
You know I bump into these questions and then I request a sneak peak into the source code just to find these precious… cough…:
<?php
/*
* Importing
*/
$reader->get('etc.csv'); // contains 500k rows
foreach($reader->rows as $row) {
$product = App\Models\Product::firstOrCreate(['sku' => $row->sku]);
$product->name = $row->name;
$product->save();
}
And I say, What the HECK is going on? Did you know, that by doing so at the best you make 1 million query to the database? 1 MILLION.
At the worst scenario you could end up doing 1.5 million queries.
- 500k SELECT
- 500k INSERT
- 500k UPDATE
This is how you import 500k rows in 20-25 minutes instead of 30-40 seconds.
If you’re using a Framework it does not mean that you need to do every single task with the “most beautiful available tool”, in this case: Eloquent.
You could just spin up a \DB::class
for this, and make this happen with a single INSERT ... ON DUPLICATE KEY UPDATE ...
query. Before you say that hey my ID is the unique here and I am not going to insert them with a predefined ID. Yes, if we stick to our example, you need to make sku
column unique also. :)
INSERT INTO products (sku, name)
VALUES
(...)
ON DUPLICATE KEY UPDATE
name = VALUES(name)
You need to “stringify” the values, you could use my snippet to do that:
<?php
function stringifyThisArray($values) {
$string = '';
for($i=0;$i<count($values);$i++) {
if($i!=0) $string .= ',';
$string .= '(';
for($j=0;$j<count($values[$i]);$j++) {
if($j!=0) $string .= ',';
$string .= sprintf("'%s'", mysql_real_escape_string($values[$i][$j]));
}
$string .= ')';
}
return $string;
}
// $values is an array of products for example:
// [ [columnValue, columnValue] ] like:
$values = [
['1234', 'Book of the damned'],
['1235', 'Book of ...']
];
// You can create values the old fashion way
$values = [];
foreach($reader->rows as $row)
array_push($values,[$row->sku, $row->name]);
Well technically the 500k rows is big so you would need to make 3 batch out of it, but you got the idea.
2nd Common Mistake: Not using the “most beautiful available tool”
Yes. I told you just a few lines before, that you do not need to use the “most…” every single time, but hear me out.
Now that we fixed that 25 minutes of “frozen browser tab” we can move to the next step. What if I tell you that it is possible to go down from 30-40 seconds to 1 second.
This is the great time to use Laravel’s Queued jobs.
Conclusion
In the most cases all frameworks are just fine. So does Laravel.
If you have performance issues please check your code, or make me check it. : ^)