Best is to take a look at the source code.
select() or get()
https://github.com/laravel/framework/blob/8.x/src/Illuminate/Database/Connection.php#L366
return $statement->fetchAll();
It uses fetchAll which loads all records into memory. This is fast but consumes a lot of memory.
cursor()
https://github.com/laravel/framework/blob/8.x/src/Illuminate/Database/Connection.php#L403
while ($record = $statement->fetch()) {
yield $record;
}
It uses fetch, it loads only 1 record into memory from the buffer at a time. Note that it only executes one query though. Lower memory but slower, since it iterates one by one. (note that depending on your php configuration, the buffer can be either stored on php side or mysql. Read more here)
chunk()
https://github.com/laravel/framework/blob/8.x/src/Illuminate/Database/Concerns/BuildsQueries.php#L30
public function chunk($count, callable $callback)
{
$this->enforceOrderBy();
$page = 1;
do {
$results = $this->forPage($page, $count)->get();
$countResults = $results->count();
if ($countResults == 0) {
break;
}
if ($callback($results, $page) === false) {
return false;
}
unset($results);
$page++;
} while ($countResults == $count);
return true;
}
Uses many smaller calls of fetchAll (by using get()), 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 its trying to use the benefit of both get() and cursor().
As a rule of thumb I would say go with chunk, or even better chunkById if you can. (chunk has bad performance on big tables since it uses offset, chunkBy id uses limit).
lazy()
In laravel 8 there is also lazy(), its similar to chunk but syntax is cleaner (uses generators)
https://laravel.com/docs/8.x/eloquent#streaming-results-lazily
foreach (Flight::lazy() as $flight) {
//
}
In does the same as chunk(), just you dont need a callback, since it uses php Generator. You can also use lazyById() similar to chunk.