Naar de inhoud
Recognized by Laravel Match je project Contact

Gebruik chunking voor grote datasets

Voor het laatst bijgewerkt op:

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() en lazyById() gebruiken id > last_id in plaats van OFFSET, 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 tot cursor()

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 platte LazyCollection teruggeeft, 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]);
});

Meer informatie

Skill

Laravel Boost Skill

Gebruik deze skill om de richtlijn rechtstreeks toe te passen met een AI-assistent.

Use this skill when a Laravel task touches this best practice. It is self-contained so it can be installed independently by Laravel Boost or another agent-skill system.

## Core Guidance

Loading thousands of records into memory at once can cause memory exhaustion and slow response times. Laravel provides several chunking and lazy collection strategies, `chunk()`, `chunkById()`, `cursor()`, `lazy()`, and `lazyById()`, each suited to different scenarios depending on whether you need relationships, are modifying records, or prioritize memory efficiency.

## Why It Matters

- **Prevents memory exhaustion**: Processing records in smaller batches keeps memory usage predictable
- **Safe during mutations**: `chunkById()` and `lazyById()` use `id > last_id` instead of `OFFSET`, preventing skipped or duplicated records when modifying data during iteration
- **Memory-efficient reads**: `cursor()` holds only one model in memory at a time via a PHP generator
- **Relationship support**: `lazy()` supports eager loading while still chunking, unlike `cursor()`

## Apply When

- Batch processing large datasets (imports, exports, notifications)
- Scheduled commands processing many records
- Reports or data transformations on large tables
- Any operation iterating over more than a few hundred records

## Be Careful When

- Small datasets where loading all records at once is fine
- Queries that return a limited number of records by design

## Canonical Source

- Full best practice: https://github.com/Dutch-Laravel-Foundation/best-practices/blob/main/database-and-eloquent-orm/use-chunking-for-large-datasets/BEST_PRACTICE.md
- Dutch translation: https://github.com/Dutch-Laravel-Foundation/best-practices/blob/main/database-and-eloquent-orm/use-chunking-for-large-datasets/translations/nl.md

## Workflow

1. Inspect the user's Laravel code before recommending changes.
2. Identify the narrow rule from this best practice that applies to the task.
3. Prefer Laravel's built-in conventions and documented APIs over custom abstractions.
4. Keep examples focused on this practice; reference other skills or practices when the task crosses boundaries.
5. Verify code changes with the project's available tests, linters, static analysis, or framework checks.

## Review Checklist

- The recommendation is Laravel-specific and grounded in this practice.
- Code examples use realistic Laravel file names, class names, and method names.
- The advice avoids mixing unrelated architecture, deployment, security, or testing topics.
- Related practices are mentioned when useful, but not re-explained in full.
- Dutch output, when requested, keeps framework and API names intact.