我想使用一个方面来创建一个简单的查询,我可以用它来获取分页数据,但是我注意到,如果我这样做,我得到的性能非常差,当相比运行两个单独的查询。
作为一个快速测试,我创建了一个包含50000个随机文档的集合,并运行了以下测试。
var x = new Date();
var a = {
count : db.getCollection("test").find({}).count(),
data: db.getCollection("test").find({}).skip(0).limit(10)
};
var y = new Date();
print('result ' + a);
print(y - x);
var x = new Date();
var a = db.getCollection("test").aggregate(
[
{
"$match" : {
}
},
{
"$facet" : {
"data": [
{
"$skip": 0
},
{
"$limit": 10
}
],
"pageInfo": [
{
"$group": {
"_id": null,
"count": {
"$sum": 1
}
}
}
]
}
}
]
)
var y = new Date();
print('result ' + a);
print(y - x);
这样做的结果是,两个单独的查询,一个是find,另一个是count,大约需要2毫秒,而聚合的单个查询需要500毫秒。
为什么聚合这么慢?
更新
在聚合中,即使只是一个没有facet的计数也是很慢的
var x = new Date();
var a = db.getCollection("test").find({}).count();
var y = new Date();
print('result ' + a);
print(y - x);
var x = new Date();
var a = db.getCollection("test").aggregate(
[
{ "$count" : "count" }
]
)
var y = new Date();
print('result ' + a);
print(y - x);
在上面的测试数据集中,聚合计数需要200ms,而Count方法需要2ms。
这个问题扩展到了NodeJs Mongodb驱动程序,其中.Count()方法已被弃用并替换为countDocuments()方法,在新的countDocuments()方法中使用聚合而不是count方法,就像我上面的例子一样,它的性能明显更差,以至于我将继续使用弃用的方法而不是新的countDocuments()方法。
3条答案
按热度按时间mm5n2pyu1#
当然慢了。
count()
方法只是在查询 * 应用 * 后返回游标大小(这并不一定要求读取所有文档,具体取决于您的查询和索引)。此外,对于空查询,查询优化器知道应该返回所有文档,基本上只需要返回length(_id_1)
。根据定义,聚合不以这种方式工作。除非有一个匹配阶段实际上排除了一个文档,否则每个文档 * 都是从“磁盘”*(MongoDB自己的缓存和FS缓存暂时放在一边)读取的,以便进一步处理。
wmomyfyw2#
我遇到了同样的问题,我只是希望任何人都可能有一个更好的答案,然后什么是以前张贴。
我有一个“用户”集合,其中有1200万用户,使用MongoDB 5.0。
我的查询看起来像这样:
查询需要大约1分钟,因此这是不可接受的。
我有一个关于“updated_at”的索引,这不是问题所在。
此外,即使我直接在Compass中的MongoShell上运行它,我也会遇到这个问题。因此,它与之前怀疑的任何NodeJs Mongo驱动程序无关。
我可以告诉Mongo使用估计的计数吗?或者有没有其他方法来改进查询?
axr492tv3#
@mustordont,你是对的,根本不要使用$facet。我刚刚从生产查询中删除了所有$facet。改进后的查询时间从6s缩短到1 ms(200万条记录)