在聚合框架中使用索引 - 理解文档

时间:2014-09-12 10:00:18

标签: mongodb mongodb-query aggregation-framework

我正在阅读MongoDB文档,更准确地说,是聚合管道。 当我读到这个chapter时,更确切地说是这句话:

  
    

即使管道使用索引,聚合仍然需要访问实际文档;即索引不能完全覆盖聚合管道。

  

我不太清楚这句话是什么意思。他们是说它可以在第一阶段使用索引但是在不可能使用它之后?那么为什么索引不能完全覆盖聚合管道?

有人可以给我一个非常好的,简单的例子,我可以理解和反例吗?

提前谢谢!

1 个答案:

答案 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()可以更好地执行,即使这意味着重构您的模式表示。