我正在阅读MongoDB文档,更确切地说是聚合管道。当我阅读本章,更准确地说,这句话时:
即使管道使用索引,聚合仍然需要访问实际文档;即索引不能完全覆盖聚合管道。
我不太明白这句话的意思。他们是说它可以在第一阶段使用索引,但在以后无法使用它吗?那么,为什么索引不能完全覆盖聚合管道呢?
有人可以给我一个很好且容易理解的示例,以及一个反例吗?
先感谢您 !
这需要对MongoDB中的“覆盖索引”查询实际上是什么有一点了解,并且许多人会弄错这一点。取得以下文件:
{ "a": 1, "b": 2 }
大多数人会犯的错误是,即使将这两个字段都添加到索引中,例如:
db.collection.ensureIndex({ "a": 1, "b": 1 })
然后他们认为这会导致“覆盖索引”查询:
db.collection.find({ "a": 1, "b": 2 }).explain(); // bah-wah!!!
但事实并非如此。原因基本上是,作为“无模式”数据存储,MongoDB无法知道“ a”和“ b”实际上是集合中每个文档中唯一的字段。因此,如果没有“投影”操作也排除_id
索引中不存在的字段,那么优化器可能无法知道索引包含检索此数据所需的所有信息。因此,除非您执行以下操作,否则它必须返回到集合:
db.collection.find({ "a": 1, "b": 2 },{ "_id": 0, "a": 1, "b": 1 }).explain(); // success!!!
那么这如何适用于聚合呢?与不同的“管道”阶段一样,没有实际的方法可以真正完成与上述相同的组合。您唯一可以做的基本上是这样的:
db.collection.aggregate([
{ "$match": { "a": 1, "b": 2 } },
{ "$project": { "_id": 0, "a": 1, "b": 1 } }
])
重要的是要使用“ unix pipe”或|
“ chaining”命令,因此即使进行了一些优化,也不是完全一样。每个管道阶段都会“传递”来自进行阶段的输出,这意味着_id
(例如,此处)实际上并没有$match
以优化的方式从前一个阶段“提取” ,即使您告诉它“离开”了。
由于$match
诸如此类的其他特殊阶段$geoNear
实际上是唯一真正可以访问索引的事物,因此,由于“字段排除”实际上并不可用,因此您不会真正获得“覆盖索引”结果。
在这里要说的最后一件事是,聚合实际上不是基本查询的“替代品”,因此不应该这样使用。您应该已经接受“正在这里做更多的工作”,并且“覆盖索引”并不是您真正想要的,因为您通常想要的数据比索引中的数据还要多。
如果所有内容都在索引中,那么它实际上可能不是聚合操作,并且最好使用basic来执行.find()
,即使这意味着重新构造模式表示。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句