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

DocumentDB聚合查询性能差异排查:生产环境查询极慢原因分析

DocumentDB聚合查询性能差异及缓存问题解答

问题描述

我们的DocumentDB集合包含70k条文档,生产环境中执行聚合查询耗时约2分48秒,但在另一性能更差的实例上,相同数据量下查询仅需6秒。我们怀疑是缓存问题,但执行db.collection.stats()未显示缓存相关信息,请问DocumentDB是否支持查询缓存?

生产环境慢查询executionStats

{
    "queryPlanner": {
        "plannerVersion": 1.0,
        "namespace": "nnnnnnnn",
        "winningPlan": {
            "stage": "LIMIT_SKIP",
            "inputStage": {
                "stage": "SORT",
                "sortPattern": {
                    "_tempSortEventId": -1.0
                },
                "inputStage": {
                    "stage": "SUBSCAN",
                    "inputStage": {
                        "stage": "COLLSCAN"
                    }
                }
            }
        }
    },
    "executionStats": {
        "executionSuccess": true,
        "executionTimeMillis": "113311.697",
        "planningTimeMillis": "0.303",
        "executionStages": {
            "stage": "LIMIT_SKIP",
            "nReturned": "50",
            "executionTimeMillisEstimate": "113310.782",
            "inputStage": {
                "stage": "SORT",
                "nReturned": "50",
                "executionTimeMillisEstimate": "113310.776",
                "sortPattern": {
                    "_tempSortEventId": -1.0
                },
                "inputStage": {
                    "stage": "SUBSCAN",
                    "nReturned": "70107",
                    "executionTimeMillisEstimate": "110684.645",
                    "inputStage": {
                        "stage": "COLLSCAN",
                        "nReturned": "70107",
                        "executionTimeMillisEstimate": "67827.520",
                        "inputStage": {
                            "nReturned": "1",
                            "executionTimeMillisEstimate": "0.048"
                        }
                    }
                }
            }
        }
    },
    "serverInfo": {
        "host": "prod",
        "port": 27017.0,
        "version": "4.0.0"
    },
    "ok": 1.0,
    "operationTime": Timestamp(1670838896,1)
}

执行的聚合请求语句

aggregate(
    [
        { 
            "$match" : 
            { 
                "ApplicationId" : NUUID("dd25dadc-6b22-4f81-995b-2cce698a111a"), 
                "FilterKeys" : 
                { 
                    "$elemMatch" : 
                    { 
                        "Name" : "CorporateId", 
                        "Value" : "bbbfe3a7-fbec-4c88-8746-adf883a2ae6b" 
                     } 
                } 
             } 
         }, 
         { 
             "$addFields" : 
             { 
                 "_tempSortEventId" : 
                 { 
                     "$toLower" : "$EventId" 
                 } 
              } 
          }, 
          { 
              "$sort" : 
              { 
                  "_tempSortEventId" : -1 
              } 
           }, 
           { 
               "$project" : 
               { 
                   "_tempSortEventId" : 0 
               } 
           }, 
           { 
               "$skip" : 0 
           }, 
           { 
               "$limit" : 50 
           }])

解答

关于DocumentDB的查询缓存支持

DocumentDB确实支持查询缓存,默认会缓存最近使用的查询计划和数据,但db.collection.stats()不会直接展示缓存相关统计。你可以通过执行db.runCommand({getParameter: 1, "queryCacheSize": 1})查看缓存大小配置,通过db.runCommand({serverStatus: 1}).queryCache查看缓存的使用情况。

不过从你的执行计划和耗时数据来看,缓存不是导致性能差异的核心原因,真正的瓶颈在于以下两点:

  1. 全集合扫描(COLLSCAN)
    执行计划显示查询触发了全表扫描,遍历了全部70107条文档,这说明没有针对$match条件创建有效索引。在性能较差的实例上查询更快,大概率是因为该实例的数据集已经完全加载到内存缓存中,避免了磁盘IO开销;而生产环境可能因为数据未缓存或有其他资源竞争,导致全表扫描耗时剧增。

  2. 内存/磁盘排序开销
    聚合中需要对所有匹配文档进行排序,执行计划的SORT阶段耗时占比极高。如果排序的数据量超过DocumentDB默认的100MB内存限制,会触发磁盘排序,这会进一步拉长查询时间。

优化建议

  • 创建针对性索引:针对$match条件创建复合索引,加速文档筛选:

    db.collection.createIndex({
        "ApplicationId": 1,
        "FilterKeys.Name": 1,
        "FilterKeys.Value": 1
    })
    

    该索引可以直接加速$elemMatch对数组元素的匹配,避免全表扫描。

  • 优化排序逻辑:

    • 考虑在文档中新增一个持久化字段(如lowercaseEventId),存储转小写后的EventId,然后针对该字段创建索引,避免聚合时动态转换和内存排序。
    • 如果无法修改文档结构,可以尝试创建包含排序字段的复合索引,让查询直接利用索引排序:
      db.collection.createIndex({
          "ApplicationId": 1,
          "FilterKeys.Name": 1,
          "FilterKeys.Value": 1,
          "EventId": 1
      })
      
      同时调整聚合逻辑,直接对EventId转小写后排序(或在索引中预先处理),尽量让排序阶段利用索引。
  • 验证缓存状态:如果仍怀疑缓存问题,可以在生产环境执行查询后再次运行,观察耗时是否下降,以此验证是否命中缓存。但优先优化索引和查询逻辑,这才是解决性能问题的根本方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 21:10:28