我正在阅读MongoDB文档,更准确地说,是聚合管道。 当我读到这个chapter时,更确切地说是这句话:
即使管道使用索引,聚合仍然需要访问实际文档;即索引不能完全覆盖聚合管道。
我不太清楚这句话是什么意思。他们是说它可以在第一阶段使用索引但是在不可能使用它之后?那么为什么索引不能完全覆盖聚合管道?
有人可以给我一个非常好的,简单的例子,我可以理解和反例吗?
提前谢谢!
答案 0 :(得分:3)
这需要了解一下"涵盖的指数"实际上是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"或|
in" chaining"命令,所以即使进行了一些优化,这也不是一回事。每个管道阶段"传递"来自前进阶段的输出,这意味着_id
(例如此处)实际上并未被提取"以优化的方式从之前的$match
开始,即使你告诉它"离开"。
由于 $match
以及 $geoNear
等其他特殊阶段实际上是唯一可以实际访问索引的内容,因此& #34;字段排除"实际上并没有真正获得"涵盖的指数"结果
最后要说的是,聚合并不是真正的替代品#34;对于基本查询,不应该这样使用。你应该已经接受了你在这里做了更多的工作"以及那个被覆盖的索引"并不是你真正想要的,因为你通常想要的数据比索引中的更多。
如果它全部在索引中,则它可能不是真正的聚合操作,并且使用基本.find()
可以更好地执行,即使这意味着重构您的模式表示。