2015-05-19 56 views
0

想象一下包含大约5,000,000个文档的集合。我需要做一个basicCursor查询来选择基于太多字段进行索引的〜100个文档。我们称之为basicCursorMatch。这将非常缓慢。我可以在MongoDB光标上做第二个'查询'吗?

但是我可以在bTreeCursor上查询几个索引,这会限制我的搜索到500个文档。我们称这个查询为bTreeCursorMatch

有没有一种方法可以直接在上做游标或从bTreeCursorMatch产生的集合?

凭直觉我试图

var cursor = collection.find(bTreeCursorMatch); 
var results = cursor.find(basicCursorMatch); 

类似collection.find(bTreeCursorMatch).find(basicCursorMatch),这似乎并没有工作。

另外,我希望我可以做这样的事情:

collection.aggregate([ 
    {$match: bTreeCursorMatch}, // Uses index 5,000,000 -> 500 fast 
    {$match: basicCursorMatch}, // No index, 500 -> 100 'slow' 
    {$sort} 
]); 

..但似乎我不能做到这一点无论是。有没有别的办法可以做我想做的事?

我问的原因是因为这第二个查询将有很大的不同,我没有办法索引所有的字段。但我确实希望使用bTreeCursor进行第一个查询,否则查询整个集合将永远使用basicCursor

更新

此外,通过用户输入的文档500的部分选定将被以不同的方式在会话期间与不可预测的basicCursor查询查询,使用多个$in$eq$gt$lt。但在此期间,bTreeCursor子选举仍然相同。我应该继续为每个用户查询做两个查询吗,还是有一种更有效的方法来保存这个集合的reference

+0

您不能连接查询,因为游标在数据库中'实时',它们已经包含查询和光标位置。但是,您可以简单地在查询末尾追加附加条件*,或者强制使用索引。 – mnemosyn

+1

使用两个$ match元素定义聚合管道可行。你收到了什么错误信息? –

+0

@Pascal Bugnion认真吗?那我一定做错了。我会尽快再试一次。这会为第一个查询使用索引吗?或者它会合并查询并使用基本光标?我使用的是MongoDB'2.4',也许这两个$匹配需要'3.0'? – Redsandro

回答

1

实际上,您很少需要在游标上运行第二个查询。您特别不需要将MongoDB的工作分解为单独的可索引/不可索引块。

如果您向MongoDB的find方法传递查询,那么可以通过在索引中查找来部分满足该方法,MongoDB将首先执行查找,然后对其余文档执行全面扫描。

举例来说,我有一个集合users与像文件:

{ _id : 4, gender : "M", ... } 

有一个指数_id,但不是性别。在users有~200M文件。

想了解一下MongoDB是引擎盖下做的一个想法,添加explain()你的光标(在蒙戈外壳):

> db.users.find({ _id : { $gte : 1, $lt : 10 } }).explain() 
{ 
    "cursor" : "BtreeCursor oldId_1_state_1", 
    "n" : 9, 
    "nscannedObjects" : 9 
} 

我已经削减了一些由explain返回的字段。基本上,光标会告诉你它是否使用索引,n告诉你查询返回的文档数,而nscannedObjects是查询过程中扫描的对象数。在这种情况下,mongodb能够精确扫描正确数量的对象。

如果我们现在查询性别,会发生什么?

> db.users.find({ _id : { $gte : 1, $lt : 10 }, gender : "F" }).explain() 
{ 
    "cursor" : "BtreeCursor oldId_1_state_1", 
    "n" : 5, 
    "nscannedObjects" : 9 
} 

find返回5个对象,但必须扫描9个文档。因此,它能够使用_id字段隔离正确的9个文档。然后它通过所有9个文件并按性别过滤它们。

+0

谢谢。我现在已经提出了这个答案(以及之前的评论)。不过,我不确定这个答案是否足够先进。我会赞扬努力增加一点复杂性。例如,实际上我经常发现'explain'返回3或5个具有不同索引的计划和游标。我已经使用基本解释来验证我的查询,但是多个计划是它令人困惑的地方。此外,处理文档的半永久性选择(参见编辑)未得到解决。例如。你会简单地为每个“子查询”合并两个查询对象吗? – Redsandro

+1

我对你的评论有点困惑。在'find'上调用'explain'会返回一个计划。如果您运行'db.collection.find()。explain({verbose:true})',您会得到一个名为'allPlans'的额外子文档,其中包含可能应用于查询的所有计划。使用的计划是解释文档顶层的计划。 –

+1

当您使用'{explain:true}'运行聚合时,您会为聚合管道中的每个阶段获得一个计划(MongoDB还会添加allPlans子文档,该文档列出了该阶段考虑的所有计划,但是顶层计划是实际执行的计划)。 –