How to read MongoDB executionStats
By Marios Pavlidis · Updated October 2026 · Applies to MongoDB 5.0–8.0, classic query engine
Getting executionStats output
Run explain("executionStats") to get the metrics that show how much work MongoDB actually did to satisfy your query:
// find query
db.orders.find({ status: "shipped", total: { $gt: 100 } })
.explain("executionStats")
// aggregate pipeline
db.orders.explain("executionStats").aggregate([
{ $match: { status: "shipped" } },
{ $group: { _id: "$category", count: { $sum: 1 } } }
])Copy the entire JSON response and paste it into the execution plan analyzer to get a visual tree with findings. This guide explains how to read the numbers directly.
The four key metrics
nReturned
The number of documents returned to the client by this stage. At the top level this is your result count. On an IXSCAN stage it is the number of index entries that matched.
totalKeysExamined
How many index entries MongoDB read. An IXSCAN with totalKeysExamined === nReturned is efficient — every key it read led to a match. A ratio much higher than 1 means the index scan is wider than it needs to be.
totalDocsExamined
How many full documents MongoDB loaded from the collection. A COLLSCAN loads every document in the collection. An IXSCAN followed by FETCH loads one document per matching key (unless a predicate is pushed into FETCH and filters further). A covered query has totalDocsExamined: 0 — all data came from the index.
executionTimeMillis
Wall-clock time for the query, measured on the server. This is a single-run observation and is affected by cache state, concurrency, and server load at the moment you ran it. Don't treat a single measurement as representative — run the query several times, check whether the data was warm in the WiredTiger cache, and consider using $currentOp or Atlas performance advisor for aggregate patterns.
Annotated example: efficient IXSCAN
The following output is illustrative — numbers are synthetic to demonstrate a well-optimized query. An index on { status: 1 } exists on the orders collection.
{
"queryPlanner": {
"winningPlan": {
"stage": "FETCH", // loads full docs after index lookup
"inputStage": {
"stage": "IXSCAN", // reads the index
"keyPattern": { "status": 1 },
"indexName": "status_1",
"direction": "forward",
"indexBounds": {
"status": ["[\"shipped\", \"shipped\"]"]
}
}
}
},
"executionStats": {
"executionSuccess": true,
"nReturned": 142, // 142 documents matched
"executionTimeMillis": 3,
"totalKeysExamined": 142, // read exactly 142 index entries
"totalDocsExamined": 142 // loaded exactly 142 full documents
}
}Interpretation: Every index key read led to a returned document (142 keys = 142 docs = 142 returned). The examination ratios are 1:1 — this index is well-matched to the query predicate. The FETCH stage is still present because the index only stores status; full documents are needed to return all fields.
Annotated example: COLLSCAN
When no usable index exists, MongoDB performs a collection scan. Illustrative example:
{
"queryPlanner": {
"winningPlan": {
"stage": "COLLSCAN", // no index — scans every document
"direction": "forward"
}
},
"executionStats": {
"nReturned": 142,
"executionTimeMillis": 380,
"totalKeysExamined": 0, // no index used
"totalDocsExamined": 85000 // examined the whole collection
}
}Interpretation: 85,000 documents examined to return 142 — a ratio of roughly 600:1. This is the typical starting point for an index investigation. Create an index on the field(s) in the query predicate, re-run the explain, and verify that totalDocsExamined drops closer to nReturned.
Interpretation limitations
- Single-run timing is noisy. Cache state, I/O, and server load all affect
executionTimeMillis. A cold explain (first run after a restart) will be slower than a warm one. Use slow-query logs for aggregate evidence. - Examination ratios are not the only signal. A 1:1 ratio on an IXSCAN is good, but a query touching a very large number of documents efficiently is still a large query. Consider whether the query result set is the right size for your use case.
- Aggregation pipelines report per-stage. Each pipeline stage has its own
nReturned. A$matchearly in the pipeline that reduces documents significantly is almost always preferable to filtering later. - The SBE engine reports differently. MongoDB 6.0+ may use the Slot-Based Execution engine for some queries. The explain shape differs from the classic engine — the analyzer detects this and shows the conceptual plan tree, but raw engine-level detail may vary.