Introductie
Duizenden records tegelijk in het geheugen laden kan leiden tot geheugenuitputting en trage responstijden. Laravel biedt verschillende chunking- en lazy collection-strategieën, chunk(), chunkById(), cursor(), lazy() en lazyById(), die elk geschikt zijn voor andere scenario's, afhankelijk van of je relaties nodig hebt, records aan het wijzigen bent, of geheugenefficiëntie prioriteit geeft.
Waarom
- Voorkomt geheugenuitputting: Records in kleinere batches verwerken houdt het geheugengebruik voorspelbaar
- Veilig tijdens mutaties:
chunkById()enlazyById()gebruikenid > last_idin plaats vanOFFSET, wat overgeslagen of gedupliceerde records voorkomt wanneer je data wijzigt tijdens het itereren - Geheugenefficiënt lezen:
cursor()houdt via een PHP-generator slechts één model tegelijk in het geheugen - Ondersteuning voor relaties:
lazy()ondersteunt eager loading terwijl er toch gechunkt wordt, in tegenstelling totcursor()
Geschikt voor
- Batchverwerking van grote datasets (imports, exports, notificaties)
- Geplande commands die veel records verwerken
- Rapporten of datatransformaties op grote tabellen
- Elke operatie die over meer dan een paar honderd records itereert
Minder geschikt voor
- Kleine datasets waarbij het prima is om alle records tegelijk te laden
- Queries die van nature een beperkt aantal records teruggeven
Voorbeelden
Basis chunking
// Bad: loads everything into memory
$users = User::all();
foreach ($users as $user) {
$user->notify(new WeeklyDigest);
}
// Good: processes in batches of 200
User::where('subscribed', true)->chunk(200, function ($users) {
foreach ($users as $user) {
$user->notify(new WeeklyDigest);
}
});
Gebruik chunkById() wanneer je records wijzigt
Standaard chunk() gebruikt OFFSET, wat verschuift wanneer rijen veranderen. chunkById() gebruikt id > last_id, wat veilig is tegen mutatie:
User::where('active', false)->chunkById(200, function ($users) {
$users->each->delete();
});
Kiezen tussen cursor() en lazy()
cursor(), één model tegelijk in het geheugen, maar kan geen relaties eager-loaden (risico op N+1)lazy(), gechunkte paginatie die een platteLazyCollectionteruggeeft, ondersteunt eager loading
// Good: attribute-only work, maximum memory efficiency
foreach (User::where('active', true)->cursor() as $user) {
ProcessUser::dispatch($user->id);
}
// Good: when you need relationships
foreach (User::with('roles')->lazy() as $user) {
echo $user->roles->count();
}
Gebruik lazyById() wanneer je wijzigt tijdens het itereren
lazy() gebruikt offset-paginatie, het wijzigen van records tijdens het itereren kan ze overslaan of dubbel verwerken. lazyById() gebruikt id > last_id, veilig tegen mutatie:
User::where('needs_update', true)->lazyById()->each(function ($user) {
$user->update(['needs_update' => false]);
});