Eloquent get() vs chunk() vs lazy() benchmarks

I did some unscientific benchmarks of the methods available in Laravel. Even the official documents describe the characteristics of each technique, I wanted a quick ”ballpark benchmark” of which one to choose. Take the exakt numbers with a big grain of salt, my point is to show the difference between the methods.

TL;DR

Tested with Laravel 8.74 and PHP 7.4.25 on macOS with Laravel Valet.

Benchmarks

10 000 records

Method Memory Time
get() 26 MB 261ms
cursor() 12 MB 460ms
lazy() 9MB 300ms
chunk() by 500 6MB 400ms

100 000 records

Method Memory Time
get() 277 MB 2.72sec
cursor() 75 MB 5.8sec
lazy() 9MB 5.4sec
chunk() by 500 6MB 7.56sec

Methods

get()

It employs under the hood fetchAll, which loads all records into memory. This is quick, but it takes up a lot of memory.

cursor()

The cursor method uses fetch and loads only one record from the buffer at a time into memory. A big drawback of this method is that cursor() cannot eager load relationships. It uses less memory but is slower because it iterates one by one. Depending on your configuration, the buffer can be stored on the PHP side or the MySQL side.

chunk()

Uses many smaller calls of fetchAll, and tries to keep memory low by breaking a big query result into smaller queries using limit depending on the chunk size you specify. In a way, it is trying to use the benefit of both get() and cursor().

lazy()

In Laravel 8, there is also lazy(), it is similar to chunking. Essentially, it does the same as chunk(). However, you don’t need a callback since it uses PHP generators and returns a LazyCollection, which makes the syntax is cleaner.