【问题标题】:Does MongoDB fetch entire document even if single field is projected?即使投影单个字段,MongoDB 是否会获取整个文档?
【发布时间】:2021-02-21 23:15:28
【问题描述】:

我有一个用于天气数据的 MongoDB 集合,每个文档包含大约 50 个不同的天气参数字段。下面的简单示例:

{
"wind":7,
"swell":6,
"temp":32,
...
"50th_field":32
}

如果我只需要所有文档中的一个字段,比如temp,我的查询将是这样的:

db.weather.find({},{ temp: 1})

那么在内部,MongoDB 是否必须只为请求(投影)的 1 个字段获取整个文档?这不是一项昂贵的手术吗?

我尝试使用 MongoDB Compass 对时间进行基准测试,但所需时间为

【问题讨论】:

    标签: mongodb mongoose mongodb-query


    【解决方案1】:

    是的。这是避免它的方法:

    1. temp 上创建索引
    2. 使用find(Temp)
    3. 关闭 _id(必需)。

    运行:

    db.coll.find({ temp:{ $ne:null }},{ temp:1, _id:0 })`
    

    {} 触发 collscan,因为算法尝试将查询字段与项目匹配

    {temp}, {temp, _id:0} 表示:“哦,我只需要临时”。

    告诉{}, {temp, _id:0} 只需要索引也应该很聪明,但事实并非如此。

    【讨论】:

    • 这不是一个好的答案。请在编辑后的问题出现时查看
    • 什么意思? @Martian2049
    • @Martian2049 索引数据总是在内存中,如果你查询 1 个被索引的字段并运行正确的查询,它会很快。
    【解决方案2】:

    MonogDB 将读取所有数据,但只有字段temp(和_id)会通过您的网络传输到客户端。如果您的文档相当大,那么当您只投影您需要获取的字段时,整体性能应该会更好。

    【讨论】:

      【解决方案3】:

      基本上使用带有限制字段的投影总是比获取完整文档更快,您甚至可以使用覆盖索引来避免检查文档(无磁盘 IO)存档更好的性能。

      查看下面demo的executionStatstotalDocsExamined是0!但是您必须删除投影中的 _id 字段,因为它不包含在索引中。

      另请参阅: https://docs.mongodb.com/manual/core/query-optimization/#covered-query

      > db.test.insertOne({name: 'TJT'})
      {
        "acknowledged" : true,
        "insertedId" : ObjectId("5faa0c8469dffee69357dde3")
      }
      > db.test.createIndex({name: 1})
      {
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
      }
      
      db.test.explain('executionStats').find({name: 'TJT'}, {_id: 0, name: 1})
      {
        "queryPlanner" : {
          "plannerVersion" : 1,
          "namespace" : "memo.test",
          "indexFilterSet" : false,
          "parsedQuery" : {
            "name" : {
              "$eq" : "TJT"
            }
          },
          "winningPlan" : {
            "stage" : "PROJECTION",
            "transformBy" : {
              "_id" : 0,
              "name" : 1
            },
            "inputStage" : {
              "stage" : "IXSCAN",
              "keyPattern" : {
                "name" : 1
              },
              "indexName" : "name_1",
              "isMultiKey" : false,
              "multiKeyPaths" : {
                "name" : [ ]
              },
              "isUnique" : false,
              "isSparse" : false,
              "isPartial" : false,
              "indexVersion" : 2,
              "direction" : "forward",
              "indexBounds" : {
                "name" : [
                  "[\"TJT\", \"TJT\"]"
                ]
              }
            }
          },
          "rejectedPlans" : [ ]
        },
        "executionStats" : {
          "executionSuccess" : true,
          "nReturned" : 1,
          "executionTimeMillis" : 0,
          "totalKeysExamined" : 1,
          "totalDocsExamined" : 0,
          "executionStages" : {
            "stage" : "PROJECTION",
            "nReturned" : 1,
            "executionTimeMillisEstimate" : 0,
            "works" : 2,
            "advanced" : 1,
            "needTime" : 0,
            "needYield" : 0,
            "saveState" : 0,
            "restoreState" : 0,
            "isEOF" : 1,
            "invalidates" : 0,
            "transformBy" : {
              "_id" : 0,
              "name" : 1
            },
            "inputStage" : {
              "stage" : "IXSCAN",
              "nReturned" : 1,
              "executionTimeMillisEstimate" : 0,
              "works" : 2,
              "advanced" : 1,
              "needTime" : 0,
              "needYield" : 0,
              "saveState" : 0,
              "restoreState" : 0,
              "isEOF" : 1,
              "invalidates" : 0,
              "keyPattern" : {
                "name" : 1
              },
              "indexName" : "name_1",
              "isMultiKey" : false,
              "multiKeyPaths" : {
                "name" : [ ]
              },
              "isUnique" : false,
              "isSparse" : false,
              "isPartial" : false,
              "indexVersion" : 2,
              "direction" : "forward",
              "indexBounds" : {
                "name" : [
                  "[\"TJT\", \"TJT\"]"
                ]
              },
              "keysExamined" : 1,
              "seeks" : 1,
              "dupsTested" : 0,
              "dupsDropped" : 0,
              "seenInvalidated" : 0
            }
          }
        }
      }

      【讨论】:

        猜你喜欢
        • 2015-04-03
        • 1970-01-01
        • 2020-01-12
        • 2014-04-17
        • 2019-07-12
        • 1970-01-01
        • 1970-01-01
        • 2015-06-06
        • 1970-01-01
        相关资源
        最近更新 更多