Understand offset vs keyset pagination when processing large datasets to avoid missing records during updates.
Updating records inside chunk() modifies the result set, causing offset pagination to skip every second chunk. Use chunkById() or lazyById() when updating query columns.
use App\Models\User;
// BAD when updating filtered column: skips records due to offset shift!
User::where('processed', false)->chunk(100, function ($users) {
$users->each->update(['processed' => true]);
});
// GOOD: Uses primary key comparison (id > last_id) to avoid skipping
User::where('processed', false)->chunkById(100, function ($users) {
$users->each->update(['processed' => true]);
});
- chunk() uses OFFSET pagination (vulnerable to skipping if queried fields change)
- chunkById() uses keyset pagination (WHERE id > last_id), safe for updates
- lazyById() provides the same keyset safety wrapped in a LazyCollection
Related Tips
View all tips →Stream Large Datasets: cursor() vs lazy() in Eloquent
cursor() hydrates single model instances sequentially using database cursors; lazy() streams records in chunks backed by LazyCollection.
Optimize Date Queries by Replacing whereYear() with whereBetween()
Replace whereYear() and whereMonth() on large database tables with whereBetween() date ranges to enable SQL index lookups.