MongoDB 聚合查询 Aggregate 性能慢如何优化索引

文章导读
MongoDB 聚合查询性能慢通常是因为管道早期阶段未命中索引,导致全表扫描。最推荐的处理方向是调整管道阶段顺序,将 $match 和 $sort 前置,并为过滤字段创建复合索引。
📋 目录
  1. 命令速用版
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 常见问题
  7. 参考来源
A A

MongoDB 聚合查询性能慢通常是因为管道早期阶段未命中索引,导致全表扫描。最推荐的处理方向是调整管道阶段顺序,将 $match 和 $sort 前置,并为过滤字段创建复合索引。

先说结论:优化核心在于减少进入聚合管道的文档数量,利用索引覆盖过滤和排序阶段。

  • 先定位:使用 explain("executionStats") 分析执行计划,确认是否发生 COLLSCAN(全表扫描)。
  • 先做:调整聚合管道顺序,确保 $match 和 $sort 位于管道前端,并创建对应复合索引。
  • 再验证:对比优化前后的 totalDocsExamined 和 executionTimeMillis 指标,确认索引生效。

命令速用版

直接执行以下命令查看当前聚合查询的执行统计信息,重点关注执行阶段和扫描文档数。

db.collection.aggregate(
  [ { $match: { status: "active" } }, { $group: { _id: "$category" } } ],
  { explain: "executionStats" }
)

为什么会这样

聚合管道按顺序处理文档,早期阶段未使用索引会导致后续阶段处理大量无效数据。MongoDB 优化器虽然会尝试重排 $match,但显式前置能确保索引被优先使用。索引只能加速 $match、$sort 和部分 $lookup,无法直接加速 $group 的哈希计算过程。

分步处理

按以下步骤操作,每一步完成后需确认执行计划变化。

步骤 1:分析当前执行计划
运行带 explain 的聚合命令。检查 output 中的 stages 字段。如果看到 inputStage 包含 "stage" : "COLLSCAN",说明未命中索引。记录 totalDocsExamined 数值。

步骤 2:调整管道阶段顺序
将 $match 阶段移动到管道最前面。将 $sort 阶段尽量靠近 $match。避免在 $match 之前使用 $project 丢弃索引字段。确保 $match 中的查询条件字段与索引字段一致,不要对字段进行表达式计算。

步骤 3:创建复合索引
根据 $match 的过滤条件和 $sort 的排序字段创建索引。索引键顺序应先等于过滤字段,后等于排序字段。例如:

db.collection.createIndex({ status: 1, createdAt: -1 })

步骤 4:回滚提醒
创建索引会占用存储空间并影响写入性能。如果在写入密集型业务,需在低峰期操作。若优化无效,可使用 db.collection.dropIndex() 删除新建索引。

MongoDB 聚合查询 Aggregate 性能慢如何优化索引

怎么验证是否生效

再次运行 explain("executionStats") 命令。检查 stages 中的 inputStage 是否变为 "IXSCAN"。对比 totalDocsExamined 是否显著下降,理想情况下应接近 nReturned 数值。观察 executionTimeMillis 是否降低。公开资料中没有看到可靠的量化数据,具体提升幅度取决于数据分布和索引选择性。

常见坑

1. $match 中使用正则表达式且未锚定开头,导致索引失效。
2. $group 阶段位于 $match 之前,导致无法利用索引过滤。
3. 对索引字段使用 $toString 或 $sum 等表达式,导致无法命中索引。
4. 排序方向与索引定义方向不一致(如索引为 1,排序为 -1),可能无法利用索引排序。

常见问题

$group 阶段能利用索引吗?

通常不能直接利用索引加速分组计算,但如果在 $group 前有 $sort 且命中索引,可减少内存排序开销。

多个索引会自动合并使用吗?

MongoDB 聚合管道通常只使用一个索引进行扫描,索引交集(Index Intersection)支持有限,建议创建覆盖所有查询条件的复合索引。

explain 中的 nReturned 代表什么?

nReturned 代表最终返回给客户端的文档数量,用于与 totalDocsExamined 对比评估索引效率。

参考来源

MongoDB Official Documentation, Aggregation Pipeline Optimization, https://www.mongodb.com/docs/manual/aggregation/

MongoDB Official Documentation, Explain Results, https://www.mongodb.com/docs/manual/reference/method/cursor.explain/