mongodb索引性能好坏取决于硬指标:indexcount、indexsize、totalsize及explain()中的nreturned、totaldocsexamined、executiontimemillis和indexbounds;复合索引需严格遵循最左前缀原则与排序方向一致性,否则失效。

MongoDB索引性能好坏,不能只看“有没有索引”,得盯住几个硬指标——它们直接决定查询快不快、内存够不够、写入扛不住。下面这几个字段,你在 db.collection.stats() 或 explain() 输出里必须一眼认出来。
stats() 里最该盯的三个索引指标
执行 db.collection.stats() 后,别被几十行输出吓住,先聚焦这三个字段:
-
indexCount:当前集合有多少个索引。超过 5–6 个就要警惕——每个索引都吃写入性能,尤其在高频更新场景下 -
indexSize:所有索引占用的总字节数。如果它接近甚至超过size(数据本身大小),说明索引已严重膨胀,比如地理空间或哈希索引容易干这事 -
totalSize=size+indexSize:这个和磁盘配额、备份窗口强相关。线上扩容前不看它,可能半夜被磁盘打满告警叫醒
explain() 中判断索引是否真起效的关键字段
查一条慢 query,光看 cursor: "BtreeCursor" 不够,得确认它是不是真的“用对了”。重点看:
-
executionStats.nReturned和executionStats.totalDocsExamined:理想情况二者应接近。如果后者是前者的几十倍,说明索引没覆盖查询条件,或者用了低选择性字段(比如status: "active"这种只有2–3个值的字段建了索引) -
executionStats.executionTimeMillis:不是越小越好,而是要结合totalDocsExamined看单位扫描成本。10ms 扫 1000 文档,比 5ms 扫 10 万文档更危险 -
queryPlanner.indexBounds:空数组或显示{},代表根本没走索引;有具体范围(如"age": ["[18, 150]"])才说明索引边界被正确计算
复合索引失效的典型信号
复合索引 {a:1, b:-1, c:1} 很容易“看着有、实际废”。常见踩坑点:
- 查询只含
b和c,跳过最左字段a→ 完全不触发索引(违反最左前缀原则) - 查询
{a: {$in: [...]}, c: 1}:中间字段b没出现,c就无法利用索引排序,sort()会 fallback 到内存或磁盘排序 - 排序方向不匹配:
find({a:1}).sort({b:1})对{a:1,b:-1}索引无效,必须严格一致或全为1
真正难的不是建索引,是持续验证它还在高效工作——索引会老化,查询会变,业务逻辑一改,昨天的最优索引今天就成拖累。定期跑 db.collection.aggregate([{$indexStats: {}}]) 看 accesses.ops,比盯着监控图更能提前发现“僵尸索引”。











