DEV Community

Cover image for MongoDB Indexing Strategies: ESR Rule, Explain Plans, and Performance Tuning
DEVANSHU PATIL
DEVANSHU PATIL

Posted on AI-assisted

MongoDB Indexing Strategies: ESR Rule, Explain Plans, and Performance Tuning

MongoDB Indexing Strategies: ESR Rule, Explain Plans, and Performance Tuning

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 });
Enter fullscreen mode Exit fullscreen mode

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):

  1. Equality: Place fields that use equality match conditions first. These fields narrow down the dataset immediately.
  2. Sort: Place fields for sorting next. The index can satisfy the sort order before scanning ranges.
  3. 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
});
Enter fullscreen mode Exit fullscreen mode

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");
Enter fullscreen mode Exit fullscreen mode

Key Metrics to Inspect in executionStats

  • executionStats.executionStages.stage: If this reads COLLSCAN, your query scanned the entire collection. If it reads IXSCAN, your query successfully leveraged an index.
  • totalDocsExamined vs nReturned: A healthy query has a ratio close to 1:1. If totalDocsExamined is 1,000,000 but nReturned is 5, your query is highly inefficient.
  • totalKeysExamined: The number of index entries scanned. High numbers compared to nReturned indicate 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
  }
}
Enter fullscreen mode Exit fullscreen mode

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 $indexStats to monitor which indexes are actually being used by the database engine.
db.orders.aggregate([{ $indexStats: {} }]);
Enter fullscreen mode Exit fullscreen mode
  • 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 on a (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)