Camkode
Camkode

10 Laravel Query Optimization Tips That Cut My Query Time by 40 Seconds

Posted by Kosal

10 Laravel Query Optimization Tips That Cut My Query Time by 40 Seconds

Recently, I optimized a Laravel query and the result blew me away.

By simply replacing whereNotIn() with leftJoin(), my query that once took over 40 seconds completed almost instantly.

The reason? I was querying a table with over 1 million records, and whereNotIn() was dragging performance down. But that’s just one of many tricks to speed up Laravel apps.

Here are 10 quick and powerful ways to make your Laravel queries faster and more efficient:


1. Replace whereNotIn() with leftJoin()

Using whereNotIn() can be slow, especially on large datasets.

A leftJoin() with a whereNull() check often runs faster by letting the database engine optimize better.

// Slower
User::whereNotIn('id', Blacklist::pluck('user_id'))->get();

// Faster
User::leftJoin('blacklists', 'users.id', '=', 'blacklists.user_id')
     ->whereNull('blacklists.user_id')
     ->select('users.*')
     ->get();

2. Replace whereIn() with whereExists()

whereIn() loads all values into memory, which can be a problem with large subqueries.

whereExists() is more efficient—it only checks for the existence of rows.

// Better performance
User::whereExists(function ($query) {
    $query->select(DB::raw(1))
          ->from('subscriptions')
          ->whereColumn('subscriptions.user_id', 'users.id');
})->get();

3. Select Only the Columns You Need

Avoid User::all() unless you really need all columns.

Fetching only the required fields reduces data transfer and memory usage.

// Instead of this
User::all();

// Do this
User::select('id', 'name')->get();

4. Process Large Data in Chunks

If you’re dealing with thousands (or millions) of rows, use chunk() to avoid memory overload.

User::chunk(1000, function ($users) {
    foreach ($users as $user) {
        // Process each user
    }
});

5. Use pluck() for Single Columns

Need just one column’s values? Use pluck()—it’s faster and uses less memory.

User::pluck('email'); // Faster than get()

6. Check with exists() Instead of count() > 0

Don’t count all rows just to check if data exists.

exists() is much quicker.

// Slower
Post::where('status', 'published')->count() > 0;

// Faster
Post::where('status', 'published')->exists();

7. Use upsert() Over updateOrInsert()

Laravel’s upsert() is optimized for fewer queries and bulk operations.

// Instead of updateOrInsert() in a loop
Model::upsert($data, ['unique_key'], ['column_to_update']);

8. Paginate Instead of Loading All Records

Avoid loading huge datasets at once—use pagination to reduce memory and load time.

User::paginate(50);

9. Cache Frequent Queries

Use Laravel’s caching system to store results of expensive queries and avoid hitting the database repeatedly.

$users = Cache::remember('active_users', 60, function () {
    return User::where('active', 1)->get();
});

10. Avoid Eager Loading in Loops

Avoid loading relationships inside loops—use load() or with() to batch them.

// Instead of this (bad)
foreach ($users as $user) {
    echo $user->profile->bio;
}

// Do this (good)
$users->load('profile');

Every Millisecond Counts

When working at scale, small changes lead to big performance wins.

Laravel gives you all the tools you just need to use them wisely.

Whether you're building SaaS, a dashboard, or an API—these optimizations can save seconds per request, reduce server load, and make your users happy.

Happy coding! 🚀