The same five queries ranked by time per call and by total time, where the slowest single query is last by total cost and a 48 millisecond query run 120,000 times is first

Slow Query Identification

Back to Performance Tuning and Capacity Planning · End-to-End Profiling · Resource Utilization Breakdown · Evidence Before Action · Service Offerings

Pulling the actual worst-performing database queries, often the single biggest win available. It frequently is the biggest win, and the reason is simple: application code runs on your CPU, while a bad query makes the database do work that no amount of application tuning can avoid.

1. Rank by Total Time, Not by Time per Call

This single choice decides whether the exercise finds anything. A slow query log sorted by duration shows you the two-second report that runs three times a day. Sorted by total time, the same data shows a 48-millisecond query run a hundred and twenty thousand times — six seconds of database work against an hour and a half.

The fast query is also the easier fix, which is the part people find surprising. It runs constantly, so any improvement compounds; and queries that run that often are usually simple enough that an index settles them.

Where to get the ranking:

2. Read the Plan, and Read the Right One

EXPLAIN shows what the planner intends. EXPLAIN ANALYZE runs the query and shows what happened, and the answer is usually in the difference between the two.

3. Why an Index Is Not Being Used

An index exists and the plan ignores it. Almost always one of these:

4. The Problem a Slow Query Log Cannot Show You

N+1 is invisible to every tool in section 1, because each individual query is fast. One query fetches fifty rows, then the ORM issues fifty more to load a relation, and the log records fifty-one unremarkable entries.

It only appears as volume: a query with an absurd call count relative to the number of page views. That is also how to find it — divide calls by requests and look for anything above one. Fixing it is usually an eager-load hint rather than anything to do with the database.

The same blindness applies to a query that is fast alone and slow under concurrency, because it holds a lock. That one shows up in lock-wait statistics, not in query duration.

5. Every Index Is a Trade

Adding an index is not free, and the cost is paid by a different part of the system from the one that benefits. Each index must be updated on every insert, update and delete to its columns, it occupies space, and it needs maintaining. A table with twelve indexes has slow writes for a reason.

6. A Worked Example From Our Own Infrastructure

A statistics page on one of our tools took 58 seconds to load, and the cause was a single SELECT count(*). In SQLite that is a full table scan, and the table had grown past fourteen gigabytes. No index helps; counting is the work.

The fix was not query optimisation at all — it was storing the count when the data is written and reading it back. 58 seconds became 0.002.

The part worth carrying away is why it went unnoticed. The same query was fast on one host and slow on another, with the same data and the same code, because one had the table in page cache and the other did not. A query is not fast or slow on its own; it is fast or slow on a particular machine in a particular state, which is why the measurement has to happen where the problem is.

How We Approach It

  1. Turn on the right collector for your database and let it gather over a representative period, including a busy one.
  2. Rank by total time, and separately by call count relative to request volume, which is what surfaces N+1.
  3. Take the top few and read their plans with timings, looking first at the gap between estimated and actual rows.
  4. Establish why — missing index, unusable index, stale statistics, a spilled sort, a lock — rather than applying the usual remedy.
  5. Change one thing and measure the same way, including the write path if an index was added.
  6. Leave the collector running, so the next regression is visible without another engagement.

What You Get

The test of this work is whether the thing you fix is the thing that was costing you. Ranked by duration, it usually is not.