← 返回题目列表

MongoDB explain 怎么看?如何判断查询有没有走索引?

高频 中等 第 16 / 31 题 更新于 2026/07/28
MongoDBexplain执行计划查询优化

简化版

MongoDB 可以用 explain() 查看查询执行计划,重点看 winningPlan、是否出现 IXSCAN、是否有 COLLSCAN、扫描文档数和返回文档数的比例、排序是否使用索引、执行耗时等。走索引不一定就快,关键是索引是否能显著减少扫描并支持排序。

详细版

常用写法:

db.orders.find({ userId: 100 }).explain("executionStats")

重点字段:

  • winningPlan:最终选择的计划;
  • IXSCAN:索引扫描;
  • COLLSCAN:集合扫描;
  • totalKeysExamined:扫描索引键数量;
  • totalDocsExamined:扫描文档数量;
  • nReturned:返回文档数量;
  • executionTimeMillis:执行耗时;
  • SORT:是否发生额外排序。

如果 totalDocsExamined 远大于 nReturned,通常说明过滤效率不高,需要检查索引、查询条件和数据分布。

完整版教学

一、explain 解决什么问题

查询慢时,不能只靠猜。explain() 能告诉我们 MongoDB 选择了什么执行计划,扫描了多少索引键和文档,是否发生全集合扫描。

例如:

db.users.find({ email: "a@example.com" }).explain("executionStats")

可以判断是否使用了 email 索引。

二、IXSCAN 和 COLLSCAN 怎么看

IXSCAN 表示使用索引扫描,通常是好信号。COLLSCAN 表示集合扫描,可能要扫描大量文档。

但不能机械认为 COLLSCAN 一定错。小集合、低选择性条件、返回大部分数据时,集合扫描可能合理。

真正要看的是:扫描量是否符合业务预期。

三、看扫描数量和返回数量

三个数字很关键:

totalKeysExamined
totalDocsExamined
nReturned

理想情况下,扫描数量和返回数量差距不要太夸张。如果返回 10 条,却扫描 100 万条,说明查询效率很差。

常见原因:

  • 缺少合适索引;
  • 复合索引字段顺序不匹配;
  • 查询条件选择性差;
  • 排序没走索引;
  • 使用了低效正则或表达式;
  • 数组字段导致索引膨胀。

四、SORT 节点可能是性能瓶颈

如果查询需要排序:

db.orders.find({ userId: 100 }).sort({ createdAt: -1 })

最好有类似索引:

db.orders.createIndex({ userId: 1, createdAt: -1 })

否则 MongoDB 可能先取出大量数据再内存排序,数据量大时性能很差。

执行计划中出现显式 SORT 时,要检查排序是否能被索引覆盖。

五、覆盖查询为什么快

如果查询需要的字段都在索引里,MongoDB 可以尽量只读索引而不回表取完整文档,这叫覆盖查询。

例如索引:

db.users.createIndex({ email: 1, name: 1 })

查询:

db.users.find(
  { email: "a@example.com" },
  { _id: 0, email: 1, name: 1 }
)

这种情况下可能减少文档读取。

六、走索引不等于查询一定优秀

面试里要特别说明:IXSCAN 是好信号,但不是最终结论。真正要看索引扫描是否足够收敛,是否还要回表读取大量文档,是否出现额外 SORT,以及返回数量和扫描数量是否匹配。

指标理想状态风险信号
totalKeysExamined接近返回量或可接受扫描大量索引键
totalDocsExamined接近 nReturned回表文档远大于返回量
nReturned符合业务分页返回少但扫描多
SORT被索引顺序支持内存排序或大量排序

比如返回 20 条订单却扫描 200000 个索引键,虽然形式上走了 IXSCAN,也说明索引选择性或复合索引顺序有问题。优化目标是让扫描范围变小,而不是只追求执行计划里出现索引名字。

七、常见误区与追问

好执行计划大致形态:
IXSCAN -> FETCH -> LIMIT

可疑执行计划:
COLLSCAN -> SORT -> LIMIT
IXSCAN 扫描 1000000 keys -> 返回 10 docs

记忆钩子:explain 不只看“有没有 IXSCAN”,还要看“扫了多少、回了多少、排没排序、耗了多久”。

  • 误区:出现 IXSCAN 就说明查询已经优化好了。 还要看扫描键数、扫描文档数、返回数和是否额外排序,低选择性索引也可能很慢。
  • 误区:COLLSCAN 一定不可接受。 小集合、返回大部分数据、低选择性条件下集合扫描可能合理,关键看扫描成本是否符合业务规模。
  • 误区:executionTimeMillis 是唯一判断标准。 时间受缓存、并发和机器状态影响,扫描数量和计划结构更能稳定反映问题。
  • 追问:totalDocsExamined 远大于 nReturned 说明什么? 通常说明过滤不够收敛、索引不合适、回表太多或查询条件选择性差。
  • 追问:执行计划里看到 SORT 怎么办? 检查排序字段能否放入复合索引,让过滤和排序按同一索引顺序完成。
  • 追问:覆盖查询为什么能减少成本? 如果过滤和返回字段都在索引中,就可以减少读取完整文档的次数,降低 I/O 和缓存压力。

八、加强记忆

MongoDB explain 看四件事:有没有 IXSCAN,有没有 COLLSCAN,扫描数和返回数差多少,排序是否被索引支持。优化目标不是形式上走索引,而是少扫文档、少排序、少回表。