为什么你的索引“没用上”?

在 MongoDB 中,创建索引 ≠ 查询变快。索引是否生效,取决于查询语句是否能“命中”索引结构。

❌ 常见误区

误区

说明

创建了单字段索引,但查询用 $or

可能无法使用索引

复合索引顺序错误

如索引 {a:1, b:1},但查询只用 b 字段

查询中包含 $regex 或 $ne

可能导致索引失效

数据类型不匹配

如字段是 string,查询用 123(数字)

核心工具:explain() 执行计划分析

explain() 是 MongoDB 的“SQL 执行计划”工具,用于查看查询的执行细节。

基本语法

db.collection.find({ ... }).explain("executionStats")

关键输出字段

字段

说明

executionStats.executionSuccess

是否执行成功

executionStats.nReturned

返回文档数

executionStats.totalDocsExamined

扫描的文档总数(越小越好)

executionStats.totalKeysExamined

扫描的索引条目数(越小越好)

executionStats.executionTimeMillis

查询总耗时(毫秒)

queryPlanner.winningPlan.inputStage.indexName

使用的索引名称

核心判断标准

  • ✅ totalDocsExamined ≈ nReturned → 索引高效
  • ⚠️ totalDocsExamined >> nReturned → 索引未命中,全表扫描!

实战:从慢查询到索引优化

场景:用户订单查询慢

// 查询:查找用户 "alice" 在 2024 年的订单
db.orders.find({username: "alice",order_date: { $gte: "2024-01-01", $lt: "2025-01-01" }
})

步骤 1:执行 explain

db.orders.find({username: "alice",order_date: { $gte: "2024-01-01", $lt: "2025-01-01" }
}).explain("executionStats")

步骤 2:分析结果

"executionStats": {"executionSuccess": true,"nReturned": 150,"totalDocsExamined": 1200000,  // 扫描了 120 万文档!"totalKeysExamined": 0,        // 索引条目为 0 → 未使用索引"executionTimeMillis": 1250
}

📌 结论:全表扫描,性能极差!

步骤 3:创建复合索引

// 创建复合索引:先按 username,再按 order_date 排序
db.orders.createIndex({ username: 1, order_date: 1 })

步骤 4:再次执行 explain

"executionStats": {"nReturned": 150,"totalDocsExamined": 150,      // 扫描文档数 = 返回数 ✅"totalKeysExamined": 150,      // 索引命中 ✅"executionTimeMillis": 15      // 耗时从 1250ms → 15ms!
}

📌 性能提升 80 倍!