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

MongoDB双计数聚合查询优化:替代$facet实现库存计算

优化方案:替代$facet的高效聚合方法

方法一:单$group阶段完成双计数统计

利用$cond和$sum在一次分组中同时统计发货和退货数量,全程可有效利用索引,性能接近单独查询的总和。

聚合语句:

[
  {
    '$match': {
      '$or': [
        { 'startID': 0, 'toID': 40 },
        { 'startID': 40, 'toID': 0 }
      ]
    }
  },
  {
    '$group': {
      '_id': null,
      'deliveries': {
        '$sum': {
          '$cond': [ { '$and': [ { '$eq': ['$startID', 0] }, { '$eq': ['$toID', 40] } ] }, 1, 0 ]
        }
      },
      'returns': {
        '$sum': {
          '$cond': [ { '$and': [ { '$eq': ['$startID', 40] }, { '$eq': ['$toID', 0] } ] }, 1, 0 ]
        }
      }
    }
  },
  {
    '$addFields': {
      'stock': { '$subtract': ['$deliveries', '$returns'] }
    }
  },
  {
    '$project': { '_id': 0 } // 可选,隐藏_id字段
  }
]

索引优化:

确保已创建复合索引:db.movement.createIndex({startID: 1, toID: 1})
这个索引能完美匹配$match中的两个$or分支,MongoDB会对每个分支使用索引扫描,然后合并结果,避免全表扫描。


方法二:用$unionWith合并两个高效查询

既然单独查询发货和退货都很快(<80ms),可以用$unionWith将两个独立的计数查询结果合并,再计算库存。这种方法的优势是每个子查询都能100%利用各自的索引,总耗时接近两个单独查询的时间之和。

聚合语句:

[
  {
    '$match': { 'startID': 0, 'toID': 40 }
  },
  { '$count': 'deliveries' },
  {
    '$unionWith': {
      'coll': 'movement',
      'pipeline': [
        { '$match': { 'startID': 40, 'toID': 0 } },
        { '$count': 'returns' }
      ]
    }
  },
  {
    '$group': {
      '_id': null,
      'deliveries': { '$max': '$deliveries' },
      'returns': { '$max': '$returns' }
    }
  },
  {
    '$addFields': {
      'stock': { '$subtract': ['$deliveries', '$returns'] }
    }
  },
  { '$project': { '_id': 0 } }
]

原理:

  • 第一个管道统计发货数,第二个管道通过$unionWith统计退货数,两者结果合并为两条文档
  • 用$group将两条文档的计数合并到一起,$max用来提取非空的计数值(因为每条文档只有一个计数字段)
  • 最后计算库存值

为什么你的$facet方案性能差?

  1. 前置$match的$facet方案:$or条件虽然能用上索引,但MongoDB需要扫描两个索引分支并合并结果,后续$facet还要对已过滤的文档再次进行两次$match过滤,相当于重复处理数据,额外增加了开销。
  2. 无前置$match的$facet方案:$facet的每个子管道都会单独扫描全表(因为没有前置过滤),完全无法利用索引,导致性能暴跌。

内容的提问来源于stack exchange,提问作者ratzownal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 13:36:29