Jak zmniejszyliśmy opóźnienie zapytań MySQL o 40% w Laravel
By Muhammad Usman • 11/13/2026 • 3 min read
Share

As a web developer, you’ve likely seen it happen: a application or SaaS dashboard runs perfectly with a few hundred test records, but as soon as production data scales up, those instant page loads turn into multi-second hangs.
Recently, while optimizing our application backends, we ran into this exact bottleneck. Large database queries were choking on JOINs and data retrieval, degrading the user experience. By taking a methodical, evidence-based approach, we were able to slash our MySQL query response times by ~40%—all without rewriting our core application.
Here is the exact step-by-step optimization playbook we used, which you can apply to your own Laravel and Next.js applications today.
Step 1: Finding the Slow Queries with EXPLAIN
You cannot optimize what you do not measure. We started by enabling the Laravel Query Log or reviewing MySQL's Slow Query Log to identify the most sluggish database transactions.
Instead of guessing, we ran MySQL’s "EXPLAIN" command directly on those queries:
EXPLAIN SELECT * FROM users JOIN orders ON users.id = orders.user_id WHERE users.status = 'active';
What we looked for:
- "ALL" in the "type" column: This means MySQL is doing a full table scan, reading every single record from disk.
- High "rows" count: MySQL is scanning thousands of rows just to return a handful.
- "Using filesort" or "Using temporary" in the Extra column: Signs of inefficient, on-disk data manipulation.
Step 2: Designing High-Impact Composite Indexes
The single biggest win came from applying the correct MySQL indexes. While indexing single columns (like user_id) helps, complex queries with filtering (WHERE) and sorting (ORDER BY) usually need "Composite Indexes" (multi-column indexes).
MySQL read-paths only use one index per table. If you search by "status" and "created_at" together, a single composite index is far more efficient.
We analyzed our most frequent database queries and ran migrations to apply targeted indexing:
Schema::table('orders', function (Blueprint $table) {
$table->index(['user_id', 'status', 'created_at']);
});
By providing MySQL with a pre-sorted composite index, we completely bypassed "FILESORT" overhead, allowing the database to retrieve targeted results instantly.
Step 3: Solving the N+1 Query Problem with Eager Loading
One of the most common silent performance killers in Laravel is the "N+1" query problem, where the application issues one query to fetch parent records, followed by N separate queries to fetch related child data.
To prevent this, we audited our Eloquent retrievals and ensured we used eager loading wherever related models were displayed:
// BEFORE: N+1 queries running
$users = User::where('status', 'active')->get();
foreach ($users as $user) {
echo $user->profile->bio; // Triggers N queries on the database
}
// AFTER: Only 2 fast queries running
$users = User::with('profile')->where('status', 'active')->get();
Step 4: Pruning with SELECT and Server Caching
Many developers write select(*) out of habit, which forces MySQL to read unused large text or JSON columns from disk and send them over the network.
We updated our heavy queries to retrieve only the exact columns needed:
$users = User::select('id', 'name', 'email')->where('status', 'active')->get();
Finally, for read-heavy, low-frequency write data, we leveraged Laravel’s Redis-backed Cache so repeated queries never even hit the database.
The Results
After introducing composite indexes, query optimization, and eager loading, our slow dashboard database transactions dropped from a sluggish 700ms average down to under 420ms—representing a dramatic 40% query latency reduction on large production datasets.
Need help diagnosing and optimizing your own slow web app, Laravel backend, or Next.js application? Let’s optimize your database! Visit my profile to message me about my Web Development and Technical SEO Optimization services.