首页/数据/NoSQL 速查/聚合性能优化要点
MongoDB99 条

聚合性能优化要点

管道性能看三条:尽早过滤、尽量走索引、控制中间结果体积;照此调整阶段顺序通常收益明显。

NoSQL 速查数据更新于 2026-10-13

聚合优化的三个杠杆

聚合管道的性能归结为三件事:尽早过滤、尽量走索引、控制中间结果体积。优化器会尽可能把后续阶段上提,但首阶段能否用上索引完全取决于写法;因此把 $match 与 $limit 放在最前、用 $project 提前瘦身、把排序与截断贴在一起,通常就能拿到大部分收益。

基本信息

适用平台MongoDB 聚合管道(4.x / 5.x / 6.x 行为有差异)
首阶段只有首阶段能用集合索引,索引无法支撑时退化为 COLLSCAN
内存上限单个阶段默认 100MB,超出需 allowDiskUse 或调整批次
验证工具explain("executionStats") 查看阶段类型、扫描数与返回数
优化器行为会做阶段合并与重排(如把 $match 上提),但不会替你改写表达式

优化清单

  • $match 前移:首阶段直接利用索引,能砍掉后续全部计算量
  • 用 $project 或 $unset 裁剪字段:越早减小文档体积,后续排序分组越轻
  • $sort 紧跟 $limit:两者相邻可走堆排序,只需保留前 N 条
  • $lookup 控制关联侧:foreignField 建索引,或改用管道式写法先过滤再关联
  • 大分组显式设置 allowDiskUse:避免 100MB 上限报错
  • 过滤条件写在 $match 而不是 $project 表达式里,前者才能裁剪输入文档

先瘦身再分组

先瘦身再分组
// 差:先分组再过滤,全量文档进入 $group
// db.events.aggregate([{ $group: { _id: "$userId", n: { $sum: 1 } } }, { $match: { n: { $gt: 10 } } }])

// 好:过滤与投影在前,中间结果只保留需要的两个字段
db.events.aggregate([
  { $match: { day: "2026-10-12", action: { $in: ["click", "buy"] } } },   // 首阶段走索引
  { $project: { userId: 1, action: 1, _id: 0 } },                        // 提前瘦身
  { $group: { _id: { userId: "$userId", action: "$action" }, n: { $sum: 1 } } },
  { $sort: { n: -1 } },
  { $limit: 20 }                                                          // 与排序相邻,可走堆排序
])

// 验证执行计划:首阶段应为 IXSCAN,且 examined 与 returned 量级接近
db.events.explain("executionStats").aggregate([/* ... */])

写法与代价对照

写法代价来源改进方向
首阶段 $match 无法走索引全集合扫描补建匹配的复合索引,或改写条件使前缀可用
$group 前字段过多中间文档体积大、哈希表占用高先 $project 去掉大字段与数组
$sort 未跟 $limit全量排序并落盘把 $limit 紧贴 $sort,或让排序命中索引
$lookup 关联侧无索引每个输入文档都要扫关联集合foreignField 建索引,或用 pipeline 形式先过滤
正则表达式匹配无法使用索引前缀改为前缀锚定正则,或改用文本索引
用 explain 的 executionStats 看三个数:返回文档数、扫描文档数、执行耗时。扫描量远大于返回量说明索引没吃到;开启 verbose 还能看到每个阶段的时间分布,定位瓶颈块更直接。
$project 里的表达式计算不会减少进入管道的文档数:真正的裁剪只能靠 $match,投影的价值在于减小后续阶段的单文档体积。

易错点

  • 把过滤条件写在 $project 的表达式里:文档没有变少,计算量全部保留,看起来像优化实则无效
  • $sort 与 $limit 之间插了其他阶段:失去堆排序机会,变成全量排序后再截断
  • 大集合上跑 $group 不开 allowDiskUse:数据量一涨就报内存限制,任务中断且没有部分结果
  • 只看返回条数判断快慢:扫描量与返回量差距大时,返回少量结果的查询也可能是最慢的那个

数据来源与参考

  • MongoDB Manual: Aggregation Pipeline Optimization
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌