πŸš€ Supercharge Your Laravel App with Highly Optimized Eloquent Queries


If you’ve ever worked on a Laravel app that suddenly started slowing down, chances are your Eloquent queries might be the culprit. As your app scales and your data grows, even seemingly small inefficiencies in queries can cause performance bottlenecks.

In this post, we’ll walk through practical, real-world tips to write highly optimized Eloquent queries. Whether you’re building an API, a dashboard, or a SaaS platform, these practices will help you improve performance and make your app more scalable and responsive.

🧠 1. Understand and Eliminate the N+1 Query Problem

The N+1 query problem happens when your app executes one query for the main model and one additional query for each related model. For example, if you’re loading 100 posts with their authors, you could accidentally fire 101 queries!

✅ Solution: Use Eager Loading

// Instead of this:
$posts = Post::all();
foreach ($posts as $post) {
    echo $post->user->name;
}

// Do this:
$posts = Post::with('user')->get();

Why it matters: with() tells Eloquent to fetch related models in a single query, drastically reducing query count and improving performance.

🕵‍♂ 2. Catch N+1 Issues Early in Development

Sometimes it’s hard to spot N+1 problems, especially in large apps. Thankfully, there’s a great package for this:

🛠 Tool: beyondcode/laravel-query-detector

Install it with:

composer require --dev beyondcode/laravel-query-detector

It will alert you in the browser or log when it detects inefficient queries.

🧬 3. Use MySQL Indexing Wisely

MySQL (and MariaDB) use B-Tree indexes to speed up query lookups. If you’re querying large tables without indexes, your database is doing full table scans β€” ouch!

⚡ Index Best Practices

  • Add indexes to columns used in:

    • WHERE clauses
    • JOIN conditions
    • ORDER BY statements
// Migration example
$table->index('email');
$table->index(['user_id', 'created_at']);

Check slow queries with:

SHOW INDEXES FROM your_table;

🎯 4. Avoid SELECT * β€” Be Specific

Fetching only what you need is both faster and more memory-efficient.

// Avoid this:
$users = User::all();

// Better:
$users = User::select('id', 'name', 'email')->get();

Especially important in APIs where payload size matters.

🧩 5. Chunking for Large Datasets

When working with thousands (or millions) of records, don’t try to load them all into memory.

✅ Use chunk()

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

This keeps memory usage low and avoids timeouts.

🛡 6. Use chunkById() for Changing Data

If your data is updated or deleted during processing, chunkById() is a safer choice:

User::chunkById(100, function ($users) {
    foreach ($users as $user) {
        // Safe for large or dynamic datasets
    }
});

It uses the primary key to paginate reliably, avoiding duplicate or missing records.

📜 7. Optimize Pagination with β€œSeek Method”

Typical pagination using LIMIT and OFFSET becomes slower as the offset increases. Instead, use “seek method” pagination:

$lastId = 100;
$posts = Post::where('id', '>', $lastId)
             ->orderBy('id')
             ->limit(20)
             ->get();

This is faster and more efficient, especially for infinite scroll APIs or mobile apps.