用explain("executionStats")需重点检查"executionStages"中stage是否为"IXSCAN"且indexName匹配预期,若为"COLLSCAN"则未走索引;分片集群下须逐个验证"shards"数组内各分片的执行阶段与nReturned,避免广播查询;性能隐患看totalDocsExamined与totalKeysExamined比值、works值及各分片executionTimeMillis差异。

怎么用 explain("executionStats") 看查询是否走对了索引
直接在 shell 或驱动里加 explain("executionStats"),不是看有没有 "executionSuccess": true,而是盯住 "executionStages" 里的 "stage" 和 "indexName"。如果 stage 是 "IXSCAN" 且 indexName 匹配你预期的索引,说明索引生效;要是看到 "COLLSCAN",就是全表扫了——哪怕数据量小、响应快,也得改。
- 聚合管道里必须对
$match阶段单独explain,整个 pipeline 的explain可能掩盖真实执行路径 -
executionStats模式会真实执行一次查询(带计时),别在生产高峰期对大集合乱跑 - 分片集群下,
explain返回的"shards"字段里每个分片都要检查,不能只看一个
分片键没被查询时,explain 里怎么识别路由失败
重点看 "shards" 数组长度和每个分片的 "executionStats.nReturned"。如果所有分片都返回结果,或只有部分分片有数据但 nReturned > 0,说明 mongos 没能精准路由,退化成广播查询。这时 "executionStats.executionTimeMillis" 通常明显偏高,且 "allPlansExecution" 里可能有多个 IXSCAN 尝试。
- 检查查询条件是否包含分片键(或前缀),不带分片键的
find/count默认广播到所有 shard -
explain结果中若出现"scatterGather"阶段,基本等于确认广播了 - 复合分片键如
{ a: 1, b: 1 },只查{ b: 123 }不触发路由,必须带a才行
executionStats 里哪些字段暴露性能隐患
别只盯着 "executionTimeMillis"。真正要扣的是 "totalDocsExamined" 和 "totalKeysExamined" 的比值:如果前者远大于后者,说明索引过滤效率低(比如用了非前缀匹配);如果两者都很大但 nReturned 很小,大概率是索引选错或查询条件没利用好索引顺序。
-
"executionStages.works"过高(远超nReturned)往往意味着大量文档被跳过,可能是索引不覆盖或排序未命中索引 - 分片环境下,各
shard的"executionTimeMillis"差异超过 3 倍,提示数据分布倾斜或某分片负载异常 -
"nReturned"为 0 但"totalKeysExamined"很大?说明索引扫描范围过大,该加更精确的查询条件或调整索引字段顺序
为什么 explain("executionStats") 有时不显示 indexName
常见于两种情况:一是查询根本没走索引(stage === "COLLSCAN"),二是用了 $text、$regex(非前缀)、$where 这类无法使用普通 B-tree 索引的操作,此时即使建了索引,explain 也不会填 indexName,但 stage 可能显示 "TEXT" 或 "IXSCAN"(取决于是否启用 text index 或 regex 是否能走索引)。
-
$regex开头带^且索引字段是前缀时,indexName才会出现;否则 fallback 到COLLSCAN - 复合索引中,如果查询只用了后半段字段(比如索引
{a:1,b:1},只查{b:1}),indexName为空,stage是"COLLSCAN" - 使用
$or时,每个分支必须各自能走索引,否则整个$or表达式降级为全表扫描
explain 输出毫无意义;路由是否生效,必须逐个核对 shards 数组里每个成员的执行阶段和返回量。











