我的藏品中有大约250万份文件。现在我要在集合中的所有记录中添加两个数组字段。但是我的更新操作需要很长时间才能完成。以下是我的查询
db.products.update({
"code": {
"$nin": [
"Tvs",
"Lg",
"Roots",
"Mix",
"A10",
"PTPL",
"Philips",
"FireFox",
"Akkade" ]
}
},
{
"$push": {
"rights": "Read",
"Acc": "K23424"
}
},
false,
true)
以上更新大约需要2分钟来更新整个集合。还有其他方法可以优化此更新查询。
修改
包括模型说明计划结果
{
"cursor" : "BtreeCursor code_1",
"isMultiKey" : false,
"n" : 106192,
"nscannedObjects" : 106192,
"nscanned" : 106197,
"nscannedObjectsAllPlans" : 106192,
"nscannedAllPlans" : 106197,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 829,
"nChunkSkips" : 0,
"millis" : 275,
"indexBounds" : {
"code" : [
[
{
"$minElement" : 1
},
"adfgfgg"
],
[
"5def354",
"akargfdc"
],
[
"34aka545dc",
"akags"
],
[
"354erak53ag345s",
"ci45t45r6rg"
],
[
"cyuikitryui7ixsg",
"gp"
],
[
"gp",
"gslbansgrp"
],
[
"gsl7878nsgrp",
"l7hrgyn"
],
[
"l678uhn",
"l6yup"
],
[
"lfghrhyhp",
"radwaregslbsg"
],
[
"radwaregslbsg",
"radwaregslbsgrs"
],
[
"radwaregslbsgrs",
"radwarers"
],
[
"rargydwarers",
"radwaresg"
],
[
"radwargyresg",
"radwaresgrs"
],
[
"radwaresgrs",
"slr6y6bsf"
],
[
"slbrtrtsf",
{
"$maxElement" : 1
}
]
]
},
"server" : "localhost:6789",
"filterSet" : false,
"stats" : {
"type" : "FETCH",
"works" : 106198,
"yields" : 829,
"unyields" : 829,
"invalidates" : 0,
"advanced" : 106192,
"needTime" : 5,
"needFetch" : 0,
"isEOF" : 1,
"alreadyHasObj" : 0,
"forcedFetches" : 0,
"matchTested" : 0,
"children" : [
{
"type" : "IXSCAN",
"works" : 106197,
"yields" : 829,
"unyields" : 829,
"invalidates" : 0,
"advanced" : 106192,
"needTime" : 5,
"needFetch" : 0,
"isEOF" : 1,
"keyPattern" : "{ code: 1.0 }",
"isMultiKey" : 0,
"boundsVerbose" : "field #0['code']: [MinKey, \"arhtgh10sg\"), (\"a1rgtrg0sg\", \"akadc\"), (\"akadc\", \"akags\"), (\"akags\", \"ctryitrrgyrtgyixsg\"), (\"crtytryityyrixsg\", \"gp\"), (\"gp\", \"gslytyybansgrp\"), (\"gstrytylbansgrp\", \"ln\"), (\"lrytryyn\", \"lyty5typ\"), (\"lty5ty5tp\", \"radwaregtryslbsg\"), (\"radwaregs454t45rgtlbsg\", \"radwaregslbsgrs\"), (\"radwa45654t6regslbsgrs\", \"radware46rs\"), (\"radwrfgarers\", \"rad456waresg\"), (\"r457423adwaresg\", \"radw34aresgrs\"), (\"ra5656dw5rty5aresgrs\", \"slbs6565656f\"), (\"slb66rty5rty5sf\", MaxKey]",
"yieldMovedCursor" : 0,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0,
"matchTested" : 0,
"keysExamined" : 106197,
"children" : []
}
]
}
}
此致 根
答案 0 :(得分:1)
问题在于,不等式运算符 $nin
不是很有选择性,因为它经常与索引的很大一部分匹配。因此,在许多情况下,带索引的 $nin
查询的效果可能不会超过必须扫描所有文档的 $nin
查询一个集合。想一想,索引对于找到匹配的东西非常有用,而不是找不到的东西。例如, $nin
查询返回集合中的每个文档但只返回一个文档,查询首先必须查看索引,然后返回文档。这是两个“查找”,而不是表格
扫描,只会查看每个文档一次。通常,如果您的查询需要使用超过一半的索引,则应重新检查查询的执行方式,或者至少采用表扫描。因此,如果您需要使用 $nin
,通常最好确保其他更具选择性的标准是查询的一部分。另请参阅Query Selectivity。
您可以使用 Bulk API 作为优化更新的方法,包括确保选择性的其他查询,在这种情况下 Bulk.find().update()
查询包含 _id
字段,该字段默认为索引,并且唯一 _id
字段的相等匹配具有高度选择性,因为它可以匹配大多数文件。提高更新速度的另一个关键是要注意MongoDB如何控制服务器如何确认数据库操作。
以下示例初始化产品集合的 Bulk()
操作构建器,并将多个更新操作添加到操作列表中。它使用有序批量操作,按顺序逐步执行(因此名称),在出现错误时停止:
var bulk = db.products.initializeOrderedBulkOp(),
counter = 0,
criteria = {
"code": {
"$nin": [
"Tvs",
"Lg",
"Roots",
"Mix",
"A10",
"PTPL",
"Philips",
"FireFox",
"Akkade"
]
}
};
db.products.find().forEach(function(doc){
bulk.find({ "_id": doc._id, "code": criteria.code }).update({
"$push": { "rights": "Read", "Acc": "K23424" }
})}
counter++;
if (counter % 1000 == 0) {
// Execute per 1000 operations and re-initialize every 1000 update statements
bulk.execute();
bulk = db.collection.initializeOrderedBulkOp();
}
})
// Clean up queues
if (counter % 1000 != 0){
bulk.execute();
}