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

MongoDB聚合查询扫描返回比过高问题及索引优化求助

MongoDB聚合查询索引优化问题

问题背景

我优化了一条MongoDB聚合查询,结果完全正确,但因Scanned Objects/Returned比值超过1000收到大量Query targeting告警,推测是集合索引不合适。该查询用于返回bookings集合中days数组内任意start日期在指定区间的预订记录,status和client为可选查询条件,也常不带这两个条件执行。已尝试多种索引并通过cursor.explain()分析,但问题未解决。

示例文档

{
  "status": 1,
  "client": ObjectId("..."),
  "customer": ObjectId("..."),
  "days": [{"start": ISODate("2023-02-01T00:00:00.000Z")}, {"start": ISODate("2023-02-02T00:00:00.000Z")}]
}

聚合管道

db.bookings.aggregate([
  {
    "$match": {
      "status": 1,
      "client": ObjectId("..."),
      "customer": ObjectId("..."),
      "days": {
        "$elemMatch": {
          "start": {
            "$gte": ISODate("2023-02-01T00:00:00.000Z"),
            "$lte": ISODate("2023-02-28T23:59:59.999Z")
          }
        }
      }
    }
  },
  {
    "$sort": {
      "createdAt": 1
    }
  }
]);

优化方案

  • 简化$match中的days条件:单条件下$elemMatch可直接替换为数组字段的直接匹配,修改后更易触发多键索引:
    "$match": {
      // ...其他条件
      "days.start": {
        "$gte": ISODate("2023-02-01T00:00:00.000Z"),
        "$lte": ISODate("2023-02-28T23:59:59.999Z")
      }
    }
    
  • 创建针对性复合索引:
    • 针对带status、client的查询场景:
      db.bookings.createIndex({status: 1, client: 1, "days.start": 1, createdAt: 1})
      
      该索引覆盖过滤条件与排序字段,MongoDB可直接通过索引完成过滤和排序,避免后续内存排序操作,大幅减少扫描文档数量。
    • 针对不带status、client的查询场景:
      db.bookings.createIndex({"days.start": 1, createdAt: 1})
      
      直接通过days.start过滤并按createdAt排序,提升基础查询的效率。
  • 验证索引有效性:执行查询后添加explain("executionStats")查看执行详情,确认executionStats.executionStages.stage为IXSCAN,且nReturned与totalDocsExamined的比值接近1,说明索引已正确生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 18:45:33