title: "MongoDB Indexing Strategies: ESR Rule, Explain Plans, and Performance Tuning"
published: true
published_at: "2026-11-20T09:00:00+05:30"
description: "Master MongoDB indexing by diving deep into the Equality, Sort, Range (ESR) rule, analyzing explain executionStats to catch COLLSCAN, and managing index overhead."
tags: [mongodb, database, backend, performance]
ai_disclosure_level: some_ai
Introduction
Indexes are foundational to scalable query performance in MongoDB. Without proper indexing, MongoDB must perform a collection scan (COLLSCAN), inspecting every document in a collection to satisfy a query. As collections grow into millions of documents, unindexed queries introduce severe latency spikes and saturate I/O subsystems.
This guide explores production-grade MongoDB indexing strategies. We will examine single-field indexes, compound indexes, the Equality, Sort, Range (ESR) rule, how to dissect execution stats via explain(), and strategies for managing index storage overhead.
1. Single Field Indexes
A single field index operates on a single field of a document. MongoDB creates an ascending index (1) by default, though descending (-1) indexes are also supported. Because MongoDB indexes are structured as B-trees, single-field indexes support fast equality matches, sorting, and range queries on that specific field.
// Create an ascending single-field index on the 'email' field
db.users.createIndex({ email: 1 });
Impact on Writes
While single-field indexes accelerate reads, every write operation (insert, update, delete) requires MongoDB to update the corresponding index entries. Maintaining too many single-field indexes on a high-throughput write collection can severely degrade write performance.
2. Compound Indexes and the ESR Rule
A compound index involves multiple fields within a single index structure. When designing compound indexes, field ordering is critical because a compound index can serve queries that match a prefix of the index.
To maximize the efficiency of compound indexes, adhere to the ESR Rule (Equality, Sort, Range):
- Equality: Place fields that use equality match conditions first. These fields narrow down the dataset immediately.
- Sort: Place fields for sorting next. The index can satisfy the sort order before scanning ranges.
-
Range: Place fields that use range conditions (e.g.,
$gt,$lt,$in, regex) last. Range queries limit the index's ability to traverse subsequent fields efficiently.
Practical ESR Example
Consider an e-commerce application querying orders where status must equal a specific value, sorted by creation date, within a specific price range:
// Query matching the ESR rule
db.orders.find({
status: "pending", // 1. Equality
price: { $gte: 50, $lte: 500 } // 3. Range
}).sort({ createdAt: -1 }); // 2. Sort
// Optimal Compound Index based on ESR
db.orders.createIndex({
status: 1,
createdAt: -1,
price: 1
});
If you placed price (Range) before createdAt (Sort), MongoDB would have to sort results in memory or use the index sub-optimally.
3. Detecting COLLSCAN and Analyzing Explain Plans
To verify whether your queries utilize indexes effectively, use the .explain("executionStats") method on query cursors. This reveals precisely how the query engine evaluated your request.
db.orders.find({
status: "pending",
price: { $gte: 50, $lte: 500 }
}).sort({ createdAt: -1 }).explain("executionStats");
Key Metrics to Inspect in executionStats
-
executionStats.executionStages.stage: If this readsCOLLSCAN, your query scanned the entire collection. If it readsIXSCAN, your query successfully leveraged an index. -
totalDocsExaminedvsnReturned: A healthy query has a ratio close to1:1. IftotalDocsExaminedis 1,000,000 butnReturnedis 5, your query is highly inefficient. -
totalKeysExamined: The number of index entries scanned. High numbers compared tonReturnedindicate a wide range scan or loose index prefix matching.
// Example snippet of a winning plan output indicating efficient IXSCAN
{
"queryPlanner": {
"winningPlan": {
"stage": "FETCH",
"inputStage": {
"stage": "IXSCAN",
"indexName": "status_1_createdAt_-1_price_1"
}
}
},
"executionStats": {
"executionSuccess": true,
"nReturned": 12,
"executionTimeMillis": 1,
"totalKeysExamined": 12,
"totalDocsExamined": 12
}
}
4. Index Size and RAM Management
Indexes provide fast access, but they consume valuable system resources. MongoDB indexes must fit into RAM (specifically the WiredTiger internal cache) for optimal performance. If your total index size exceeds available RAM, MongoDB must perform disk paging to read index nodes, causing significant latency spikes.
Best Practices for Index Management
-
Audit Unused Indexes: Use the MongoDB aggregation framework with
$indexStatsto monitor which indexes are actually being used by the database engine.
db.orders.aggregate([{ $indexStats: {} }]);
-
Drop Redundant Indexes: If you have a compound index
{ a: 1, b: 1 }, you do not need a separate single-field index on{ a: 1 }because the compound index can serve queries filtering solely ona(index prefix property). - Limit the Number of Indexes: Avoid indexing every field 'just in case'. Aim for a balance where frequent read queries are optimized without crippling write operations or exhausting RAM.
Conclusion
Effective MongoDB performance tuning relies on disciplined index architecture. By designing compound indexes around the Equality, Sort, Range (ESR) rule, validating execution plans with explain("executionStats"), and actively auditing index sizes and usage, you can maintain predictable, low-latency data access at scale.

Top comments (0)