Index Performance and Query Plans in MongoDB (explain())

Table of Contents

  1. Introduction
  2. Why Index Performance Matters
  3. The MongoDB Query Execution Process
  4. Understanding the explain() Method
  5. Output Modes of explain()
  6. Key Metrics in explain() Output
  7. Comparing Query Plans with and without Indexes
  8. Interpreting Common explain() Scenarios
  9. Index Performance Tips and Query Optimization
  10. Tools for Index Performance Monitoring
  11. Conclusion

1. Introduction

When building data-driven applications with MongoDB, indexes play a pivotal role in ensuring performance, especially for large-scale systems. But how do you know if your indexes are being used effectively? That’s where MongoDB’s explain() method comes in.

The explain() method is a powerful diagnostic tool that reveals the query execution plan — including whether an index is used, how efficiently, and what operations were performed during the query execution.


2. Why Index Performance Matters

Poorly designed or unused indexes can lead to:

  • Full collection scans (COLLSCAN)
  • High CPU and memory consumption
  • Increased query response time
  • Slower writes due to index maintenance overhead

By analyzing query plans with explain(), developers and DBAs can ensure optimal performance, particularly for high-traffic applications.


3. The MongoDB Query Execution Process

Before we dive into explain(), let’s understand what happens when you run a query:

  1. Parsing: MongoDB parses the query to understand the fields and values.
  2. Plan Selection: It selects one or more query plans using the Query Planner.
  3. Plan Evaluation: MongoDB tests a few candidate plans (if multiple exist).
  4. Execution: It picks the best one based on efficiency and executes the query.

explain() allows you to see this planning and execution process in action.


4. Understanding the explain() Method

MongoDB’s explain() can be called on any query, update, or delete operation.

jsCopyEditdb.users.find({ email: "[email protected]" }).explain()

This will return a detailed JSON document describing how the query is executed, including whether an index was used and what type of scan was performed.


5. Output Modes of explain()

There are three verbosity levels you can use:

  • “queryPlanner” (default): Shows index selection and query plan details.
  • “executionStats”: Includes actual run-time stats like documents examined, keys examined, etc.
  • “allPlansExecution”: Shows details for all considered plans, not just the winning one.

Example with mode:

jsCopyEditdb.users.find({ email: "[email protected]" }).explain("executionStats")

6. Key Metrics in explain() Output

Here are some important fields to monitor in the output:

  • winningPlan: The actual plan used by MongoDB.
  • stage: Whether it’s COLLSCAN, IXSCAN, FETCH, etc.
  • indexName: Shows which index (if any) was used.
  • nReturned: Number of documents returned.
  • keysExamined: Number of index keys scanned.
  • docsExamined: Number of documents scanned (should be low if index is effective).
  • executionTimeMillis: Time taken to execute the query (only in executionStats).

7. Comparing Query Plans With and Without Indexes

Let’s run a query with no index:

jsCopyEditdb.customers.find({ name: "Alice" }).explain("executionStats")

This might return a plan with:

jsonCopyEdit"stage": "COLLSCAN",
"docsExamined": 100000,
"nReturned": 1

Now, create an index:

jsCopyEditdb.customers.createIndex({ name: 1 })

Run the same query:

jsCopyEditdb.customers.find({ name: "Alice" }).explain("executionStats")

You’ll likely see:

jsonCopyEdit"stage": "IXSCAN",
"docsExamined": 1,
"nReturned": 1

This demonstrates the dramatic impact of indexes on performance.


8. Interpreting Common explain() Scenarios

Scenario 1: Collection Scan

jsonCopyEdit"stage": "COLLSCAN"

No index used. Should be optimized with appropriate indexing.

Scenario 2: Index Scan

jsonCopyEdit"stage": "IXSCAN"

The query uses an index — great for performance.

Scenario 3: Covered Query

If projection is used and only index fields are returned:

jsonCopyEdit"stage": "PROJECTION_COVERED"

Covered queries skip document fetch, making them extremely fast.


9. Index Performance Tips and Query Optimization

  • Always profile slow queries with explain("executionStats").
  • Minimize docsExamined and keysExamined — they indicate work done.
  • Use covered queries where possible.
  • Avoid full scans on large collections unless intentional (e.g., reports).
  • Compound Indexes should match field order used in queries.
  • Use hint() to force index usage if the optimizer doesn’t pick the right one.

Example:

jsCopyEditdb.customers.find({ name: "Alice" }).hint({ name: 1 }).explain()

10. Tools for Index Performance Monitoring

MongoDB Atlas Performance Advisor

Automatically suggests indexes based on real workload.

mongotop and mongostat

CLI tools that show read/write activity and bottlenecks.

Application Logs

Enable query profiling to log slow operations.

jsCopyEditdb.setProfilingLevel(1, { slowms: 50 }) // Log queries > 50ms

11. Conclusion

MongoDB’s explain() is an indispensable tool for anyone serious about optimizing performance. By using it consistently during development and in production monitoring, you can:

  • Ensure indexes are being used effectively
  • Minimize expensive collection scans
  • Guide decisions for index creation and query restructuring