Profiler不能直接识别缺失索引,需结合explain("executionStats")和system.profile中nScannedObjects与nReturned比值(>10)、keysExamined低等指标交叉验证,COLLSCAN或IXSCAN阶段异常表明索引缺失或设计不当。

Profiler 能直接暴露缺失索引的查询,但必须配合 explain("executionStats") 和 system.profile 中的扫描指标交叉验证,否则容易把“慢”误判为“没索引”。
查 system.profile 里高 nScannedObjects 的操作
缺失索引最典型的信号不是耗时长,而是扫描文档数远大于返回数。在 system.profile 中过滤出 nScannedObjects 显著高于 nReturned(比如比值 >10)的记录:
-
nScannedObjects高 +keysExamined低 → 很可能全表扫描,没走索引 -
nScannedObjects和nReturned接近 → 可能命中了索引,但索引选择不佳(比如只用了前缀) - 注意:
docsExamined在写操作中对应扫描量,update/delete 里这个值异常高也指向缺失索引
用 explain("executionStats") 复现并确认执行计划
从 system.profile 拿到慢操作的原始命令(如 find 或 update),在 shell 里重放并加 explain("executionStats"):
- 重点看
executionStats.nReturned和executionStats.totalDocsExamined是否匹配 profile 里的数值 - 检查
queryPlanner.winningPlan.stage:如果是COLLSCAN,就坐实没索引;如果是IXSCAN,再看indexName是否是你预期的那个 - 聚合操作要逐 stage 看,
$match阶段没走索引,后面所有阶段都白优化
识别复合索引覆盖不全的场景
单字段有索引,但查询用了多个条件,仍可能触发扫描。Profiler 不会直接告诉你“缺复合索引”,得靠组合判断:
- 查询含
{ a: 1, b: 2 },已有{ a: 1 }索引,但system.profile显示nScannedObjects很大 → 检查是否该建{ a: 1, b: 1 } -
explain中indexBounds只对第一个字段生效,第二个字段没约束 → 复合索引顺序错了,b 应该前置或调整键序 - 排序字段不在索引中?
explain里出现stage: "SORT"且memLimitExceeded: false,说明内存够但没用索引排序 → 补上sort字段到索引末尾
真正难的是那些“看起来走了索引,实际效率极低”的情况——比如范围查询后跟等值匹配,索引顺序反了,或者嵌套字段路径没对齐。这时候 system.profile 的数字只是起点,explain 的执行树才是真相。别跳过 inputStage 嵌套结构,它藏了真实扫描逻辑。











