$ lexprog.com

// notes from an old coder -- php, databases, and the occasional rant

[February 19, 2026] Eloquent ORM

Eloquent Cursor: Memory Efficiency

Eloquent Cursor: Memory Efficiency

────────────────────────────────────────────────────────

Eloquent Cursor: Memory Efficiency

Tip: Basic Cursor

foreach (User::cursor() as $user) {
    process($user);
}

Yields one model at a time.

Gotcha: No Eager Loading

cursor() doesn't support with(). Load relations manually within the loop.

Tip: lazy() for Chunked Cursor

User::lazy(500)->each(fn($user) => process($user));

Processes 500 at a time, balancing memory and performance.

Gotcha: Cursor and Updates

Updating models during cursor iteration can cause issues. Use chunkById() instead.

Tip: Cursor with Conditions

foreach (User::where('active', true)->cursor() as $user) {
    process($user);
}

Gotcha: PDO Cursor

Under the hood, cursor uses PDO's unbuffered queries. Not all databases support this equally well.

Tip: Use cursor() for Memory-Neutral Iteration

When exporting 100K rows, get() loads everything into memory. cursor() uses yield and keeps memory flat regardless of row count. Perfect for artisan commands.

Tip: whereHas() vs load() — Two Different Things

whereHas() filters the parent query by relationship existence. load() eager-loads relationships AFTER the query. Mixing them up is a common source of logic bugs.

Gotcha: withCount() Adds a Subquery

withCount('comments') runs a correlated subquery on every row. On large tables, this can be slower than a separate query. Profile before relying on it.

Senior Insight

Laravel's cursor() method uses PHP generators to iterate large datasets with constant memory usage. It's excellent for exports and data migrations, but it has a critical limitation: the underlying PDO connection must stay open for the entire iteration. If a cursor iteration takes 10 minutes and the database's wait_timeout is 300 seconds, the query fails midway. For long-running cursor operations, I increase the connection timeout or use chunked queries instead.

Source: Laravel Docs (https://laravel.com/docs/eloquent), Laravel News (https://laravel-news.com/), Freek.dev (https://freek.dev/tags/eloquent)

────────────────────────────────────────────────────────
<-- back to posts