You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB聚合管道[$match、$project、$group]哪种执行顺序性能更优?

结论

第二种查询(先执行$match再执行$project)性能更优,二者存在实质性的性能差异,在你描述的10万1000万文档量、单文档15MB的场景下差距会被大幅放大。

核心原因
  • 索引利用效率差异:如果transaction_code字段建有索引,$match放在聚合管道第一阶段可以直接命中索引,不需要扫描全量文档、也不需要加载全量文档到内存处理。如果把$project放在第一阶段,必须先读取所有文档做字段裁剪,再执行过滤,完全无法利用索引的优势,全表扫描的开销会非常高。
  • 数据处理量级差异:$match前置会先过滤掉所有不符合条件的文档,假设最终只有20%的文档满足transaction_code="buy"的条件,后续$project只需要处理这20%的文档做字段裁剪,CPU、内存开销仅为$project前置方案的1/5。反过来如果先做$project,需要先给全量千万级别的大文档做字段裁剪,哪怕大部分文档后续会被直接丢弃,这部分开销完全是无效消耗。
  • 符合MongoDB聚合优化规则:MongoDB本身的聚合查询优化器会优先将过滤类操作前置,减少后续阶段的处理压力,$match前置的写法也更适配数据库本身的优化逻辑。
额外优化建议

你当前的场景里其实可以省略显式的$project阶段:$group仅用到account_id字段,$match仅用到transaction_code字段,MongoDB聚合管道会自动做字段投影优化,仅加载查询需要的两个字段,不会加载其他无关的大字段,性能会比显式写$project更好。

两个查询的对比参考

低性能写法($project前置)

db.getCollection('temp123').aggregate([
  {
    $project: {
      account_id: 1,
      transaction_code: 1
    }
  },
  {
    $match: {
      transaction_code: "buy"
    }
  },
  {
    $group: {
      _id: "$account_id",
      count: {
        $sum: 1
      }
    }
  }
])

高性能写法($match前置)

db.getCollection('temp123').aggregate([
  {
    $match: {
      transaction_code: "buy"
    }
  },
  {
    $project: {
      account_id: 1,
      transaction_code: 1,
      
    }
  },
  {
    $group: {
      _id: "$account_id",
      count: {
        $sum: 1
      }
    }
  }
])

内容的提问来源于stack exchange,提问作者Sree Karthik S R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 09:30:05