我有一个拥有1000万到1500万条目的mongodb数据库。对于它们中的每一个,我必须更新最初不存在的字段。假设应用程序因服务器意外关闭而崩溃,如何更新剩余的条目?
我应该使用field: {$exists: false}
并更新它们,还是应该浏览整个集合并检查每个文档是否包含该字段,如果有,请执行更新?我对此的看法是,由于您无法将索引与字段的存在关联起来,因此$ exists基本上是相同的。哪一个更快,为什么?
请注意,此字段的值将取决于文档的其他字段,因此我无法进行多次更新。
解决方案:正如@DhruvPathak和@Sammaye建议的那样,索引与数据相关联,而不是字段本身(因此您无法将索引链接到字段的存在) ,$ exists可以利用字段存在的文档中的索引,这大大提高了速度。
附加:虽然它有点像副作用,但我现在知道应用程序崩溃的原因。服务器超时了游标,因为它的使用时间太长(给定集合的大小)。如here所解释的那样使用batch_size
可以避免这种情况。
答案 0 :(得分:2)
我对此的看法是,因为您无法将索引与字段的存在相关联
根据MongoDB 2.6,它现在可以:
> use f
switched to db f
> db.t.insert({a:1})
WriteResult({ "nInserted" : 1 })
> db.t.ensureIndex({b:1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
> db.t.find({b:{$exists:false}})
{ "_id" : ObjectId("53e88a7dde0848171584d296"), "a" : 1 }
> db.t.find({b:{$exists:false}}).explain()
{
"cursor" : "BtreeCursor b_1",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 1,
"nscanned" : 1,
"nscannedObjectsAllPlans" : 1,
"nscannedAllPlans" : 1,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"b" : [
[
null,
null
]
]
},
"server" : "ubuntu:27017",
"filterSet" : false
}
>
从我可以发现它似乎是从v2.0开始添加的内容:https://stackoverflow.com/a/7503114/383478不幸的是,该答案中的文档链接已经死亡。
因此,除非您拥有v2.0之前的版本,否则查询显然会更快。
答案 1 :(得分:1)
您的查询附加explain()
将显示$exists
的光标类型为Basic
:这意味着它将扫描集合中的所有文档。因此,您可以遍历整个集合并检查每个文档是否包含该字段,如果有,则执行更新。 $exists
的性能类似于完整扫描集合。
答案 2 :(得分:1)
是的,你是对的,在这两种情况下,mongodb将迭代整个集合。
另一个实现此目的的好方法是在此字段上创建索引,
使用$exists
运算符选择目标值,然后删除索引。
确保创建的索引不是稀疏的,因为它在$ exists情况下没有帮助。
http://docs.mongodb.org/manual/core/index-sparse/