1. 课程导入与性能工程视角

MongoDB 的索引与查询性能工程,不是“背几条索引规则”就能掌握的技能。它更像一门围绕数据访问路径展开的系统工程:同一份数据,在不同查询模式、不同索引设计、不同执行计划下,可能表现出几十倍甚至上百倍的延迟差异。本课程的目标,是让你从“会写查询”进阶到“能设计访问路径、能定位性能瓶颈、能用数据证明优化有效”。

一、先建立性能工程视角

很多开发者第一次遇到慢查询时,第一反应是“加索引”。但索引并不是越多越好:每个索引都会占用内存与磁盘,并让写入路径变长。性能工程的核心,是在读性能、写性能、存储成本与一致性之间做可量化的权衡。因此,我们需要先明确三个问题:

  • 查询在做什么:是点查、范围扫描、排序、聚合,还是多条件组合?
  • 数据如何被访问:走集合扫描还是索引扫描?索引是否覆盖了过滤与排序字段?
  • 代价有多大:扫描了多少文档、返回了多少文档、耗时多少、是否命中内存?

这三个问题对应了本课程的主线:查询模式 → 索引结构 → 执行计划 → 度量指标 → 优化决策。索引不是孤立对象,而是查询与存储之间的“访问路径契约”。

二、核心问题域与知识框架

本课程围绕五个相互关联的问题域展开。第一是索引模型:单字段、复合、多键、文本、地理空间、哈希、通配符等索引分别适合什么查询。第二是查询形态:等值、范围、排序、投影、聚合管道如何影响索引选择。第三是执行计划:MongoDB 如何通过查询规划器选择 winning plan,以及 explain 输出中的 stage、indexBounds、keysExamined、docsExamined 等字段如何解读。第四是性能度量:延迟、吞吐、扫描效率、选择性、工作集与缓存命中率。第五是工程治理:索引生命周期、写入放大、慢查询日志、性能回归与容量评估。

下面这张图给出了本课程的整体知识框架与度量闭环。它强调:查询模式驱动索引设计,索引设计影响执行计划,执行计划产生可观测指标,指标反过来修正索引与查询。

MongoDB 索引与查询性能工程 · 知识框架 查询模式 → 索引结构 → 执行计划 → 度量指标 → 优化决策 查询模式 点查 / 范围 / 排序 聚合 / 多条件组合 读写比例与频率 索引结构 单字段 / 复合 / 多键 文本 / 地理 / 哈希 覆盖索引与选择性 执行计划 COLLSCAN / IXSCAN FETCH / SORT / LIMIT indexBounds 与 stage 度量指标 延迟 / 吞吐 / 扫描量 keysExamined docsExamined / 命中率 优化决策与工程治理 索引增删 · 复合字段顺序 · 覆盖查询 · 写入放大权衡 慢查询日志 · 性能回归 · 容量评估 · 索引生命周期 指标反馈修正索引与查询 示例度量(假设数据): 查询 {status:"A", createdAt:{$gt:...}} 排序 createdAt: 无索引:docsExamined=120000,耗时 480ms 复合索引 {status:1, createdAt:-1}:docsExamined=37,耗时 2ms

三、性能度量:不要只看“快不快”

延迟是最直观的指标,但它不足以解释问题。一个查询从 500ms 降到 5ms,可能只是因为数据被缓存了,而不是索引变好了。因此,我们需要一组更细的度量:

指标含义优化判断
executionTimeMillis执行阶段耗时端到端延迟的主要部分
totalKeysExamined扫描的索引键数量越接近返回文档数越好
totalDocsExamined扫描的文档数量远大于返回数说明索引选择性差
nReturned最终返回文档数与扫描量对比判断效率
stage执行阶段类型COLLSCAN 通常需要优化

一个实用的判断原则是:扫描效率 = nReturned / totalDocsExamined。如果这个比值接近 1,说明索引定位精准;如果只有 0.01,说明扫描了大量无关文档。例如,某集合有 10 万条订单,查询 {status:"PAID", city:"杭州"} 返回 200 条,但 docsExamined 为 80000,则扫描效率为 0.0025,说明缺少合适的复合索引或字段顺序不合理。

四、从“写查询”到“设计访问路径”

本课程后续会反复使用一个分析动作:用 explain("executionStats") 观察执行计划。下面是一个典型示例,用于说明我们关注什么:

db.orders.find({
  status: "PAID",
  createdAt: { $gt: ISODate("2024-01-01") }
}).sort({ createdAt: -1 }).explain("executionStats")

在输出中,我们重点看 winningPlan 的 stage 链、indexBounds 是否精确、totalKeysExamined 与 totalDocsExamined 是否接近 nReturned。如果出现 SORT 阶段且内存占用高,说明排序没有走索引;如果出现 COLLSCAN,说明查询没有可用索引。这些判断不依赖猜测,而是由执行计划直接给出。

学习建议:每学一个索引类型,都准备一个最小数据集和一条典型查询,用 explain 对比“有索引”和“无索引”的扫描量差异。把指标变化记录下来,比记住结论更有价值。

五、本课程的学习目标

完成本课程后,你应该能够:

  • 根据查询模式设计单字段、复合、多键、文本、地理空间等索引;
  • 读懂 explain 输出,判断查询是否走索引、是否覆盖、是否排序;
  • 使用 keysExamined、docsExamined、nReturned 等指标定位低效查询;
  • 在读写性能之间做权衡,避免索引膨胀与写入放大;
  • 建立慢查询监控、索引评审与性能回归的工程习惯。

性能工程不是一次性调优,而是持续观测、假设、验证、修正的循环。索引是手段,查询是入口,执行计划是证据,度量指标是判断依据。接下来,我们将从索引的基本结构与选择性开始,逐步建立这套可验证的性能工程方法。