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

MongoDB 4.4.12聚合查询IXSCAN高keysExamined问题排查求助

MongoDB 4.4.12聚合查询性能异常问题排查

场景描述

使用MongoDB 4.4.12版本,mycoll集合包含数百万级文档,myId字段设有唯一索引。执行以下聚合查询:

db.mycoll.aggregate([
  { $match: {
      $and: [
        { 'myId': { $in: [~ 1000 constants] } } 
      ]
    }
  }
])

发现即使查询的queryHash与planCacheKey相同,且$in中的ID数量均约为1000,性能差异却极大:有的查询keysExamined为8000、耗时1000ms,有的keysExamined达350000、耗时50000ms,文档扫描数与数据读取量也相差悬殊,且该现象与是否重新规划查询无关。

更新:查询计划对比

带$and与不带$and的查询计划一致,关键片段如下:

...
        "optimizedPipeline" : true,
        "winningPlan" : {
            "stage" : "FETCH",
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "myId" : 1
                },
                "indexName" : "myId",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "myId" : [ ]
                },
                "isUnique" : true,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "myId" : [
                        "[\"id1\", \"id1\"]",
                        ...,
                        "[\"idX\", \"idX\"]"
                    ]
                }
...          

问题解答

1. 仅查询1000个ID,为何唯一索引对应的keysExamined数值会如此之大?

  • 索引范围扫描逻辑:MongoDB处理$in条件时,会将每个ID转化为独立的索引范围(如["id1","id1"])。如果这些ID在索引中的分布极度分散,MongoDB需要逐个遍历每个范围对应的索引节点,过程中会扫描大量索引节点,导致keysExamined远大于目标ID数量。
  • 不存在ID的索引查找:若$in中的部分ID不存在于集合中,MongoDB仍会在索引中定位该ID的位置,这个查找过程会被计入keysExamined,即使最终没有匹配到文档。
  • 索引碎片影响:数百万级文档的集合若经历过大量写入、删除或更新操作,索引容易产生碎片。碎片会导致MongoDB需要扫描更多的索引块才能定位到目标条目,直接拉高keysExamined和查询耗时。

2. 多余的$and是否是性能差异的原因,换成不带$and的查询能否提升性能?

从查询计划的optimizedPipeline: true可以看出,MongoDB查询优化器已经自动将多余的$and语法优化掉了——带$and和不带$and的查询执行逻辑完全一致,不会产生性能差异。

因此换成如下不带$and的查询不会提升性能:

db.mycoll.aggregate([
  { $match: 
    { 'myId': { $in: [~ 1000 constants] } } 
  }
])

性能差异的根源不在语法层面,建议从以下方向排查:

  • 检查myId索引的碎片率,必要时执行db.mycoll.reIndex()或重建索引
  • 分析$in中ID在索引中的分布情况,若分散度过高,可考虑分批查询或调整数据存储策略
  • 监控查询时的内存缓存命中率,若部分查询的目标数据不在内存中,会导致磁盘IO耗时增加

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 01:01:03