Hey folks,
Just some research that I did in the past, to compare the normal Collection
and LazyCollection
of Laravel when querying for the data from Database.
Some useful notes for you if you haven't researched for it.
Let's go.
Quick introductions
Normal Collection: when querying for a set of records, it will immediately query and hydrate the models.
->get()
Would get all records if you don't add the
->limit()
Lazy Collection: won't query until you actually invoke any methods and get the data by chunk
->lazy()
->lazyById()
->lazyByIdDesc()
->cursor()
: this one is different, it would get all the data but won't hydrate the models at once and also can't be eager-loaded
PROs of Lazy indeed, save memory. But there will be consequences/trade-offs, are you ready?
Deep-dive into LazyCollection
Example Query
$users = User::select(['id', 'name'])
->orderBy('id')
->lazy();
Every Collection interaction will result in a Query to DB
Yes. Every time you invoke any method, it would query to the DB:
->first()
=> will doSELECT id,name FROM users ORDER BY id LIMIT 1
->last()
=> will do a query->isEmpty()
=> will do a query->isNotEmpty()
=> will do a query...
๐ฑ๐ฑ๐ฑ
Unlike the normal Collection
which data would be loaded at once in the memory, then you handle things on the memory.
You don't want to ram the DB on the HTTP layer, do you? Not to mention, too many queries will slow down your endpoints.
Avoid using count
method
Using count
would result in N queries. For example, if you do the count
for 15k records with lazy(1000)
, it would do:
SELECT id,name FROM users ORDER BY id LIMIT 1000 OFFSET 0
SELECT id,name FROM users ORDER BY id LIMIT 1000 OFFSET 1000
...
SELECT id,name FROM users ORDER BY id LIMIT 1000 OFFSET 16000
And then it will do the sum => cost you 16 queries to the database. Each query can take up to 50ms (depending on your DB's specs)
Horrible ๐ฑ, IKR?
Imagine using this on HTTP Layer, it would take a big amount of time and slow down the endpoint.
Conclusion
Well, I can put it like this:
If you're going to get a normal amount of records (eg 10, 20, 100 even 500), normal
get
would serve you right and there won't be many issues.Also only get the needed columns (
->get(['id', 'name', ...])
) too.Collection over Query Builder as well.
If you're going to handle a gigantic amount of records (eg 10k, 20k,...),
lazy
would be the right choice, in order to handle things gently and save memory in the long run.- You won't probably handle 10k records on the HTTP layer, will you? ๐คฃ
Or TL;DR:
Normal Collection: on HTTP with not-so-many records (up to 1k)
Lazy Collection: on Queue/Console with the big amount (1k+)
Use it wisely, alright? Don't put everything in LazyCollection
, use the right tool for the right job.
Cheers and happy speedup!