在巨大的 mongodb 集合中快速搜索非常稀有的字段
quickly search for very rare field in a huge mongodb collection
我有一个包含约 10 亿个文档的庞大集合,这些文档中很少(少于 200 个)包含一些字段“rare_field
”。
我怎样才能尽快找到包含该字段的所有文档?
如果我只是这样做:
collection.find({ "rare_field" : { $exists : true }})
超时了。
这可能需要几天时间才能完成,所以我不确定即使通过查询标志来防止超时也会有所帮助,但也许我错了。
我也可以编写一个脚本来遍历所有文档,但这会很慢,因为它需要通过网络将所有 10 亿个文档传递到我的服务器,我想要一些不需要任何传递的解决方案线上数据,很快。
注意:这是一个 sharded
合集。
我会 post 我目前的解决方案作为答案,但我不确定它是否 100% 正确,而且它没有我想要的那么快。
一个可能的解决方案是使用 findOne
而不是 find:
var doc = collection.findOne({ "rare_field" : { $exists : true }});
然后循环得到下一个:
var doc = collection.findOne({ _id : { $gt : doc._id}, "rare_field" : { $exists : true }});
但是,我不能 100% 确定这些调用一定会给我按 _id
排序的结果,而且我不确定单个 findOne
也不会超时。
我担心显式添加 sort({_id : 1})
会强制查询获取所有结果,然后传递第一个结果。
如果 rare-field
上没有索引,在最坏的情况下,mongodb 将需要遍历集合中的所有文档。在这种情况下游标可能会超时,因此您需要为游标添加一个标志以防止它这样做。
在 mongo shell 中,这意味着这样的查询:
var cursor = db.collection.find({ "rare_field" : { $exists : true }}).noCursorTimeout();
如果您担心网络问题或其他问题会在游标填充 batchSize 匹配文档之前中断查询,那么您确实可以按照您在答案中建议的那样逐一获取文档,但是您需要按 { _id: 1 }
排序,并使用 noCursorTimeout()
和 limit(1)
,即:
var doc = db.collection.find({ "rare_field" : { $exists : true }})
.sort({ _id: 1 })
.limit(1)
.noCursorTimeout()
.next();
然后按照您的建议,通过在向查询对象添加条件 { _id: { $gt: doc._id } }
的同时重复查询来检索下一个文档。
我有一个包含约 10 亿个文档的庞大集合,这些文档中很少(少于 200 个)包含一些字段“rare_field
”。
我怎样才能尽快找到包含该字段的所有文档?
如果我只是这样做:
collection.find({ "rare_field" : { $exists : true }})
超时了。 这可能需要几天时间才能完成,所以我不确定即使通过查询标志来防止超时也会有所帮助,但也许我错了。
我也可以编写一个脚本来遍历所有文档,但这会很慢,因为它需要通过网络将所有 10 亿个文档传递到我的服务器,我想要一些不需要任何传递的解决方案线上数据,很快。
注意:这是一个 sharded
合集。
我会 post 我目前的解决方案作为答案,但我不确定它是否 100% 正确,而且它没有我想要的那么快。
一个可能的解决方案是使用 findOne
而不是 find:
var doc = collection.findOne({ "rare_field" : { $exists : true }});
然后循环得到下一个:
var doc = collection.findOne({ _id : { $gt : doc._id}, "rare_field" : { $exists : true }});
但是,我不能 100% 确定这些调用一定会给我按 _id
排序的结果,而且我不确定单个 findOne
也不会超时。
我担心显式添加 sort({_id : 1})
会强制查询获取所有结果,然后传递第一个结果。
如果 rare-field
上没有索引,在最坏的情况下,mongodb 将需要遍历集合中的所有文档。在这种情况下游标可能会超时,因此您需要为游标添加一个标志以防止它这样做。
在 mongo shell 中,这意味着这样的查询:
var cursor = db.collection.find({ "rare_field" : { $exists : true }}).noCursorTimeout();
如果您担心网络问题或其他问题会在游标填充 batchSize 匹配文档之前中断查询,那么您确实可以按照您在答案中建议的那样逐一获取文档,但是您需要按 { _id: 1 }
排序,并使用 noCursorTimeout()
和 limit(1)
,即:
var doc = db.collection.find({ "rare_field" : { $exists : true }})
.sort({ _id: 1 })
.limit(1)
.noCursorTimeout()
.next();
然后按照您的建议,通过在向查询对象添加条件 { _id: { $gt: doc._id } }
的同时重复查询来检索下一个文档。