Currently Available: Need a skilled Software Developer for your next project?
Categories
Laravel

Optimizing Laravel Database Seeders for Performance

Seeding large datasets in Laravel can be really slow. Here's how to optimize your seeders for better performance.

Problem

Consider this typical seeder approach:

public function run()
{
    foreach ($teams as $team) {
        Project::factory()->count(100)->create([
            'team_id' => $team->id
        ]);
    }
}

This seems simple, but it's incredibly inefficient because it:

  • Creates individual database transactions for each record
  • Triggers model events for each creation
  • Runs validations and other overhead for each record

Solution

Here are key strategies to dramatically improve seeder performance:

1. Use Bulk Insertions

Instead of creating records one by one, batch them:

// Bad: Individual insertions
Project::factory()->count(100)->create();

// Good: Bulk insertion
$projects = Project::factory()->count(100)->make()->toArray();
Project::insert($projects);

2. Chunk Large Datasets

When dealing with thousands of records, chunk them to manage memory:

collect($projects)->chunk(100)->each(function ($chunk) {
    Project::insert($chunk->toArray());
});

3. Prepare Data in Memory First

Collect all data before touching the database:

// Prepare all data first
$projects = [];
$projects = array_merge($projects, Project::factory()->count(100)->make()->toArray());
$projects = array_merge($projects, Project::factory()->count(50)->make()->toArray());

// Then insert in one go
collect($projects)->chunk(100)->each(function ($chunk) {
    Project::insert($chunk->toArray());
});

4. Handle JSON and DateTime Fields Properly

When using bulk insertions, you need to manually format special fields:

$projects = collect($projects)->map(function ($project) {
    return array_merge($project, [
        'created_at' => now()->format('Y-m-d H:i:s'),
        'settings' => isset($project['settings']) ? json_encode($project['settings']) : null,
    ]);
});

Real-World Example

Here's a complete example that implements all these optimizations:

public function run(): void
{
    $teams->each(function ($team) {
        $now = now()->format('Y-m-d H:i:s');
        $projects = [];

        // Prepare data in memory
        $projects = array_merge($projects, 
            Project::factory()->count(300)
                ->for($team)
                ->make()
                ->map(function ($item) use ($now) {
                    return [
                        'team_id' => $item->team_id,
                        'name' => $item->name,
                        'description' => $item->description,
                        'settings' => isset($item->settings) ? json_encode($item->settings) : null,
                        'created_at' => $now,
                        'updated_at' => $now
                    ];
                })
                ->toArray()
        );

        // Bulk insert in chunks
        collect($projects)->chunk(100)->each(function ($chunk) {
            Project::insert($chunk->toArray());
        });
    });
}

Trade-offs to Consider

These optimizations can make your seeders run 10-100x faster, but there are some trade-offs:

  • Model events won't fire
  • Timestamps aren't automatically set
  • You'll need to handle relationships manually
  • Validation rules aren't checked
What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Subscribe to my newsletter

Get new posts when I publish them.

I respect your privacy. Unsubscribe at any time.

One thought on “Optimizing Laravel Database Seeders for Performance

  1. Thank you for this complete explanation, including realistic code examples and mentioning trade-offs. This allows developers to fully grasp the topic at hand and make informed decisions on whether to use this approach.

Leave a Reply

Your email address will not be published. Required fields are marked *