首页 > 解决方案 > mongoDB非分片集合中的多线程最佳实践

问题描述

我有一个相对较大的 1TB 数据库,带有 3x 层嵌套数组,但没有分片,我发现运行 100 个并行线程比使用 forEach() 处理所有数据库以从最后一层提取一些字段(10h 而不是 80h)更快。所以我的问题是:我是否可以根据从默认文档 _id 中提取的日期将数据拆分为块,或者在多个并行线程而不是 1 中处理集合中所有数据的最佳实践是什么,是否有任何简单的选项可以拆分?一次将数据等分到所有线程?

(做 skip() / limit() 似乎很耗时且无效)

这是单个文档示例:

db.m.findOne()
{
"_id":ObjectId("56c5e1ca4537ddec8950ed20"),
"f":"xyz",
"apps":[

{
"aID":"mnk",
"aDate":"20210101",
"apId":"test1",
"proc":[
         {
          "procID":1,
      "procDate":"202101",        
      "s":{   
           "c":{     "t":[ {"sid":1 } ,{"sid":2} , {"sid":4}  ]},
           "d":{    "t":[ {"sid":7} , {"sid":46}  ]} ,
           "a":{    "t":[ {"sid":12 } ,{"sid":22} , {"sid":54}  ]} ,
          }
     },
     {
      "procID":2,
      "procDate":"202102",        
      "s":{   
           "c":{     "t":[ {"sid":200 }  ]},
           "d":{    "t":[ {"sid":700} , {"sid":200}  ]} ,
           "a":{    "t":[ {"sid":1 } ,{"sid":220}  ]} ,
          }
     }
     
    ]

}

]

}

这是我尝试根据“apps.proc.procDate”字段拆分查询并使其成为多线程:

cursor = collection.aggregate([
    {"$unwind"  : "$apps"}, 
    {"$unwind"  : "$apps.proc"},
    {"$match"   : {"apps.proc.procDate" : date}},
    {"$limit"   : LIMIT},
    {"$project" : {
        "F_ID"          : "$f",
        "A_ID"          : "$apps.apId",
        "P_ID"          : "$apps.proc.procID",
        "SRC_ID_SET"    : 
  {"$setUnion" : [ 
 "$apps.proc.s.c.t.sid","$apps.proc.s.d.t.sid","$apps.proc.s.a.t.sid"             
 ]} 
  ,
        "_id"   : 0
    }}
  ])

但我觉得可以更好...

标签: mongodb

解决方案


不完全清楚你的最终意图是什么。

{"$unwind"  : "$apps"}, 
{"$unwind"  : "$apps.proc"},
{"$match"   : {"apps.proc.procDate" : date}},
{"$limit"   : LIMIT}

可以写成

{
  $set: {
     apps: {
        $map: {
           input: "$apps",
           as: "app",
           in: {
              $mergeObjects: [
                 "$$app",
                 {
                    proc: {
                       $slice: [{
                          $filter: {
                             input: "$$app.proc",
                             cond: { $eq: ["$$this.procDate", date] }
                          }
                       }, LIMIT]
                    }
                 }
              ]
           }
        }
     }
  }
}

为了

{
  "$project": {
     "F_ID": "$f",
     "A_ID": "$apps.apId",
     "P_ID": "$apps.proc.procID",
     "SRC_ID_SET": { "$setUnion": ["$apps.proc.s.c.t.sid", "$apps.proc.s.d.t.sid", "$apps.proc.s.a.t.sid"] },
     "_id": 0
  }
 }

另一种方法是

{
  $set: {
     apps: {
        $map: {
           input: "$apps",
           as: "app",
           in: {
              A_ID: "$$app.apId",
              P_ID: "$$app.proc.procID",
              SRC_ID_SET: {
                 $setUnion: {
                    $reduce: {
                       input: { $concatArrays: ["$$app.proc.s.c.t.sid", "$$app.proc.s.d.t.sid", "$$app.proc.s.a.t.sid"] },
                       initialValue: [],
                       in: { $concatArrays: ["$$value", "$$this"] }
                    }
                 }
              }
           }
        }
     }
  }
}

你仍然需要经营一些化妆品,但我想你已经了解了它的基本概念。


推荐阅读