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

MongoDB聚合查询未使用索引,执行全表扫描问题求助

问题:聚合管道未使用索引,触发全表扫描

基于MongoDB搭建的分析系统,运行聚合管道时未利用已创建的school_id索引,而是扫描了全部2139951+条文档。已为school_id字段创建索引,每个学校仅对应500-1000条记录,以下是聚合查询代码、匹配条件及执行计划截图,寻求解决办法:

聚合查询代码

const collection = mongoose.connection.db.collection('analytics');

const pipeline = [
  {
    $facet: {
      last1Min: [
        {
          $match: match,
        },
        {
          $group: {
            _id: '$visit_uid',
            url: {$first: '$url'},
            page_title: {$first: '$page_title'},
            flag: {$first: '$flag'},
            country_name: {$first: '$country_name'},
            created_at: {$first: '$created_at'},
            user: {$first: '$user'},
          },
        },
        {
          $project: {
            _id: 1,
            visit_uid: '$_id',
            url: 1,
            flag: 1,
            created_at: 1,
            user: 1,
            country_name: 1,
            page_title: 1,
          },
        },
        {
          $sort: {
            created_at: -1, // Sort by created_at field in descending order (most recent first)
          },
        },
      ],
      last5Mins: [
        {
          $match: last5MinsMatch,
        },
        {
          $group: {
            _id: '$visit_uid',
            url: {$first: '$url'},
            page_title: {$first: '$page_title'},
            id: {$first: '$id'},
            flag: {$first: '$flag'},
            country_name: {$first: '$country_name'},
            created_at: {$first: '$created_at'},
            user: {$first: '$user'},
          },
        },
        {
          $project: {
            _id: 0,
            visit_uid: '$_id',
            url: 1,
            id: 1,
            flag: 1,
            created_at: 1,
            user: 1,
            country_name: 1,
            page_title: 1,
          },
        },
        {
          $sort: {
            created_at: -1, // Sort by created_at field in descending order (most recent first)
          },
        },
      ],
    },
  },
];

return collection.aggregate(pipeline).explain("executionStats")

匹配条件

{
  "match": {
    "school_id": 2460,
    "created_at": {
      "$gte": "2024-03-02T09:53:29.828Z"
    },
    "user": {
      "$exists": true
    }
  },
  "last5MinsMatch": {
    "school_id": 2460,
    "created_at": {
      "$gte": "2024-03-02T09:49:29.828Z",
      "$lt": "2024-03-02T09:53:29.829Z"
    },
    "user": {
      "$exists": true
    }
  }
}

执行计划截图

执行计划截图

解决方案建议
  • 创建复合索引:单一school_id索引无法覆盖你的匹配条件(同时过滤school_id、created_at范围和user存在性),创建复合索引:
    db.analytics.createIndex({school_id: 1, created_at: -1, user: 1})
    
    该索引能让MongoDB快速定位指定学校、时间范围内且包含user字段的文档,直接避免全表扫描。
  • 验证索引生效:创建索引后重新执行聚合并查看explain结果,确认executionStats.totalDocsExamined降至500-1000区间,同时executionStats.executionStages.inputStage.stage显示为IXSCAN(索引扫描)而非COLLSCAN(集合扫描)。
  • 优化聚合逻辑:
    • 确保$match始终是每个子管道的第一步(当前已实现),尽早过滤无关数据。
    • 若user字段在绝大多数文档中都存在,可考虑移除user: {$exists: true}条件,减少索引字段数量,提升索引效率。
    • 由于聚合后需要按created_at降序排序,复合索引中created_at设为-1(降序)可让MongoDB直接利用索引排序,避免内存中二次排序的开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 03:37:45