如果我进行计数查询,我会在< 2seconds
中得到结果db.coll.find({"A":1,"createDate":{"$gt":new Date("2011-05-21"),"$lt":new Date("2013-08-21")}}).count()
这使用以下索引
db.coll.ensureIndex({"A":1,"createDate":1})
类似地,有4列A,B,C,D(值总是0或1),我运行4个计数查询并得到< 10seconds的结果。
我查看了聚合框架文档并创建了一个聚合查询来一起完成所有4个总和。
db.coll.aggregate( { $match : {"createDate":{$gt:new Date("2013-05-21"),$lt:new Date("2013-08-21")} } },
{ $group :
{ _id:null,
totalA : { $sum : "$A" },
totalB : {$sum: "$B},
totalC:{$sum: "$C"},
totalD:{$sum: "$D"}}}
)
我还创建了一个索引:
db.coll..ensureIndex({"createDate":1,"A":1,"B":1,"C":1,"D":1})
根据文档,该索引涵盖了我的聚合函数。但聚合的返回时间约为18秒。
我在这里很困惑。有没有什么基本的我错过或有任何基本概念落后,这使得聚合慢于计数。 我还担心由于从获取计数的代码中从mongo触发的查询数量而导致的开销。
答案 0 :(得分:7)
首先,虽然没有记录2.4.8,但您可以使用db.runCommand
调用运行解释:
db.runCommand({
aggregate: "coll",
pipeline: [
{ $match :
{"createDate":{$gt:new Date("2013-05-21"),$lt:new Date("2013-08-21")} }
},
{ $group : {
_id:null,
totalA: {$sum :"$A"},
totalB: {$sum: "$B"},
totalC: {$sum: "$C"},
totalD: {$sum: "$D"}
}}
],
explain: true
})
这会让您对正在发生的事情有所了解。
此外,您主要是将 apple 与 oranges 进行比较。
当您在查询上发出count()
时,它使用游标结果属性来获取匹配的文档数。
在聚合下,您正在选择扩展匹配,然后将所有这些结果压缩为所有项目的总和。如果您的初始$匹配结果很多,那么所有这些都需要与$ sum一起进行。
看看解释,并尝试从概念上理解差异。聚合非常适合您通常希望它做的事情。但也许这不是最好的用例。
答案 1 :(得分:4)
简短回答:在你的情况下,聚合速度较慢,因为它涉及更多数据处理,而使用索引mongo可以有效地计算计数。聚合用于计算一些复杂的结果(grouping
等),而简单计算count()
就足够了。
原因是mongodb中的聚合是一个聚合数据的框架,它基于数据处理流水线的概念。 Mongo逻辑上将整个集合传递到聚合管道。这就是整个聚合没有explain
的原因(截至本文时,版本2.4
)。这意味着基本上有一种访问方法,其余的时间用于处理。但似乎支持explain
in recent versions.
您可以对使用集合中的数据子集进行早期过滤。
早期过滤
如果您的聚合操作只需要a中的一部分数据 集合,使用
$match
,$limit
和$skip
阶段来限制 在管道开头输入的文档。当放置在 在管道的开头,$ match操作使用合适的索引 仅扫描集合中的匹配文档。放置$ match管道阶段,然后在开始时放置
$sort
阶段 管道在逻辑上等同于具有排序的单个查询 并且可以使用索引。如果可能,将$ match运算符放在 管道的开始。