【问题标题】:optimize mongoid find query performance优化 mongoid 查找查询性能
【发布时间】:2018-04-13 11:32:17
【问题描述】:

我有一个存储 user_id(外键)和 address_id(外键)的 mongo 集合。该集合目前拥有超过 500 万条记录。我有 3 个分片,集合被分片为

db.adminCommand({shardCollection: "my_db.user_addresses", key: { user_id: 1, address_id: 1}})

解释查询状态

pp UserAddress.where(id: '5ace54343b816c0cdf4b2aa9').explain
{"queryPlanner"=>
  {"mongosPlannerVersion"=>1,
   "winningPlan"=>
    {"stage"=>"SHARD_MERGE",
     "shards"=>
      [{"shardName"=>"ShardOne",
        "connectionString"=>
         "ShardOne/ip-xxx-xx-0-111:17018,ip-xxx-xx-9-99:17017",
        "serverInfo"=>
         {"host"=>"ip-xxx-xx-9-99",
          "port"=>17017,
          "version"=>"3.6.3",
          "gitVersion"=>"9586e557d54ef70f9ca4b43c26892cd55257e1a5"},
        "plannerVersion"=>1,
        "namespace"=>"my_db.user_addresses",
        "indexFilterSet"=>false,
        "parsedQuery"=>
         {"_id"=>{"$eq"=>BSON::ObjectId('5ace54343b816c0cdf4b2aa9')}},
        "winningPlan"=>
         {"stage"=>"SHARDING_FILTER", "inputStage"=>{"stage"=>"IDHACK"}},
        "rejectedPlans"=>[]},
       {"shardName"=>"ShardTwo",
        "connectionString"=>
         "ShardTwo/ip-xxx-xx-9-222:11018,ip-xxx-xx-9-66:11017",
        "serverInfo"=>
         {"host"=>"ip-xxx-xx-9-66",
          "port"=>11017,
          "version"=>"3.6.3",
          "gitVersion"=>"9586e557d54ef70f9ca4b43c26892cd55257e1a5"},
        "plannerVersion"=>1,
        "namespace"=>"my_db.user_addresses",
        "indexFilterSet"=>false,
        "parsedQuery"=>
         {"_id"=>{"$eq"=>BSON::ObjectId('5ace54343b816c0cdf4b2aa9')}},
        "winningPlan"=>
         {"stage"=>"SHARDING_FILTER", "inputStage"=>{"stage"=>"IDHACK"}},
        "rejectedPlans"=>[]},
       {"shardName"=>"ShardThree",
        "connectionString"=>
         "ShardThree/ip-xxx-xx-9-143:88888,ip-xxx-xx-0-87:88887",
        "serverInfo"=>
         {"host"=>"ip-xxx-xx-0-87",
          "port"=>88887,
          "version"=>"3.6.3",
          "gitVersion"=>"9586e557d54ef70f9ca4b43c26892cd55257e1a5"},
        "plannerVersion"=>1,
        "namespace"=>"my_db.user_addresses",
        "indexFilterSet"=>false,
        "parsedQuery"=>
         {"_id"=>{"$eq"=>BSON::ObjectId('5ace54343b816c0cdf4b2aa9')}},
        "winningPlan"=>
         {"stage"=>"SHARDING_FILTER", "inputStage"=>{"stage"=>"IDHACK"}},
        "rejectedPlans"=>[]}]}},
 "executionStats"=>
  {"nReturned"=>1,
   "executionTimeMillis"=>1,
   "totalKeysExamined"=>1,
   "totalDocsExamined"=>1,
   "executionStages"=>
    {"stage"=>"SHARD_MERGE",
     "nReturned"=>1,
     "executionTimeMillis"=>1,
     "totalKeysExamined"=>1,
     "totalDocsExamined"=>1,
     "totalChildMillis"=>0,
     "shards"=>
      [{"shardName"=>"ShardOne",
        "executionSuccess"=>true,
        "executionStages"=>
         {"stage"=>"SHARDING_FILTER",
          "nReturned"=>0,
          "executionTimeMillisEstimate"=>0,
          "works"=>1,
          "advanced"=>0,
          "needTime"=>0,
          "needYield"=>0,
          "saveState"=>0,
          "restoreState"=>0,
          "isEOF"=>1,
          "invalidates"=>0,
          "chunkSkips"=>0,
          "inputStage"=>
           {"stage"=>"IDHACK",
            "nReturned"=>0,
            "executionTimeMillisEstimate"=>0,
            "works"=>1,
            "advanced"=>0,
            "needTime"=>0,
            "needYield"=>0,
            "saveState"=>0,
            "restoreState"=>0,
            "isEOF"=>1,
            "invalidates"=>0,
            "keysExamined"=>0,
            "docsExamined"=>0}}},
       {"shardName"=>"ShardTwo",
        "executionSuccess"=>true,
        "executionStages"=>
         {"stage"=>"SHARDING_FILTER",
          "nReturned"=>0,
          "executionTimeMillisEstimate"=>0,
          "works"=>1,
          "advanced"=>0,
          "needTime"=>0,
          "needYield"=>0,
          "saveState"=>0,
          "restoreState"=>0,
          "isEOF"=>1,
          "invalidates"=>0,
          "chunkSkips"=>0,
          "inputStage"=>
           {"stage"=>"IDHACK",
            "nReturned"=>0,
            "executionTimeMillisEstimate"=>0,
            "works"=>1,
            "advanced"=>0,
            "needTime"=>0,
            "needYield"=>0,
            "saveState"=>0,
            "restoreState"=>0,
            "isEOF"=>1,
            "invalidates"=>0,
            "keysExamined"=>0,
            "docsExamined"=>0}}},
       {"shardName"=>"ShardThree",
        "executionSuccess"=>true,
        "executionStages"=>
         {"stage"=>"SHARDING_FILTER",
          "nReturned"=>1,
          "executionTimeMillisEstimate"=>0,
          "works"=>2,
          "advanced"=>1,
          "needTime"=>0,
          "needYield"=>0,
          "saveState"=>0,
          "restoreState"=>0,
          "isEOF"=>1,
          "invalidates"=>0,
          "chunkSkips"=>0,
          "inputStage"=>
           {"stage"=>"IDHACK",
            "nReturned"=>1,
            "executionTimeMillisEstimate"=>0,
            "works"=>1,
            "advanced"=>1,
            "needTime"=>0,
            "needYield"=>0,
            "saveState"=>0,
            "restoreState"=>0,
            "isEOF"=>1,
            "invalidates"=>0,
            "keysExamined"=>1,
            "docsExamined"=>1}}}]},
   "allPlansExecution"=>
    [{"shardName"=>"ShardOne", "allPlans"=>[]},
     {"shardName"=>"ShardTwo", "allPlans"=>[]},
     {"shardName"=>"ShardThree", "allPlans"=>[]}]},
 "ok"=>1.0,
 "$clusterTime"=>
  {"clusterTime"=>
    #<BSON::Timestamp:0x31dbca5d @increment=475, @seconds=1523618199>,
   "signature"=>
    {"hash"=><BSON::Binary:0x2786 type=generic data=0x57ecb8e45eee5178...>,
     "keyId"=>6537488309583609875}},
 "operationTime"=>
  #<BSON::Timestamp:0x21ebf9be @increment=474, @seconds=1523618199>}

问题在于,new relic 指出这是所有数据库查询中最耗时的查询。

Avg response time: 50,100 ms
Min: 1.37ms
Max: 62400 ms
Throughput: 104 cpm

我们如何优化查找查询?

【问题讨论】:

    标签: mongodb query-optimization sharding


    【解决方案1】:

    Min: 1.37ms, Max: 62400 ms 表明问题不在于查询本身,而在于集群,例如当其中一个碎片挂起一分钟时。 "stage"=&gt;"IDHACK" 基本上说再优化它会很棘手。

    我不明白你为什么首先将它分片。 500 万个文档 x 50 个字节,每个文档占用不到半 GB。您可以轻松地放入单个分片的内存中,并使用覆盖索引使查询速度极快。

    【讨论】:

    • 500 万份文档只是冰山一角。我需要迁移大约 3.5 亿个文档。这是参考这个stackoverflow.com/questions/48605000/…
    • 说,如果我备份数据库并且转储再次基于新的分片键或没有分片键,它会工作吗?集合中的文档仅包含这两个外键。由于该表将包含大量记录,因此我们决定对其进行分片。
    • 很公平。 3.5 亿略大于 500 万。嵌入 ID 是一种选择吗?我明白了,因为您有 n:m 关系,但是对于分片集合,您不能使用查找,这将使其使用起来非常不方便。改进此特定查询的唯一方法是根据 id 哈希创建分片键,因此查询会命中单个分片。它将长响应的机会减少 3,但可能会影响其他查询的性能。
    • 嵌入不是一个选项,因为关联记录的数量很大。无论如何,如果基于新的分片键或没有分片键恢复备份的 mongodb 数据库,它会工作吗?
    • 没有分片键就不能有分片集合。你总是需要正好 1。
    猜你喜欢
    • 1970-01-01
    • 2021-12-06
    • 2016-12-01
    • 2020-07-05
    • 2013-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-26
    相关资源
    最近更新 更多