#mongodb #mongodb#debugging

Debugging MongoDB queries with explain('executionStats')

totalKeysExamined, totalDocsExamined, nReturned — the three numbers I look at first, and what their ratios tell me before I read a single index.

AD
Admin
DevDash Editor
Published
May 04, 2026
Read time
9 min
Difficulty
Intermediate
Debugging MongoDB queries with explain('executionStats')

When a query is slow, the instinct is to look at the indexes. That's usually the right instinct — but reading raw index definitions tells you what exists, not what the planner chose. explain() tells you what actually happened.

The three modes

MongoDB's explain() takes one of three verbosity levels:

JavaScript
db.collection.find(query).explain();                    // queryPlanner
db.collection.find(query).explain("executionStats");    // + actual counts
db.collection.find(query).explain("allPlansExecution"); // + rejected plans

Start with "executionStats" every time. "queryPlanner" tells you what the planner intended to do; "executionStats" tells you what it did.

The three numbers that matter

JSON
{
  "nReturned":          12,
  "totalKeysExamined":  4821,
  "totalDocsExamined":  4821,
  "executionTimeMillis": 38
}

The ratio totalKeysExamined / nReturned — call it your selectivity score — tells you almost everything:

Note

If totalDocsExamined is much higher than nReturned but totalKeysExamined is low, the index is selective but the documents aren't. This usually means your projection needs work, not your index.

Reading the stage tree

The executionStages key gives you a tree of plan stages. The most important ones:

Stage What it means
COLLSCAN Full collection scan. No index used.
IXSCAN Index scan. Check keysExamined.
FETCH Fetch from heap after index. Normal.
SORT In-memory sort. Check memUsage.
SORT_MERGE Merging pre-sorted index results. Usually fine.

A SORT stage at the top of the tree with memUsage above 32MB means MongoDB spilled to disk. That's never fast.

When the planner picks the wrong index

MongoDB caches plan selections per query shape. If you've changed your data distribution since the cache was populated, the cached plan might be stale. Clear it:

JavaScript
db.collection.getPlanCache().clear();

Then run the query again. If explain() now shows a better plan, you've found a cache staleness bug.

Next steps

Once you've read the stats and found your COLLSCAN or high key ratio, the next article covers how to structure the index correctly using the ESR rule.

AD
Written by
Admin
DevDash Editor

Deep technical writing on databases, performance engineering, and the infrastructure that keeps production running. All articles are reviewed and published by the DevDash editorial team.