Mongodb使用facet进行聚合缓慢计数

flvlnr44  于 2023-06-22  发布在  Go
关注(0)|答案(3)|浏览(232)

我想使用一个方面来创建一个简单的查询,我可以用它来获取分页数据,但是我注意到,如果我这样做,我得到的性能非常差,当相比运行两个单独的查询。
作为一个快速测试,我创建了一个包含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()方法。

mm5n2pyu

mm5n2pyu1#

当然慢了。count()方法只是在查询 * 应用 * 后返回游标大小(这并不一定要求读取所有文档,具体取决于您的查询和索引)。此外,对于空查询,查询优化器知道应该返回所有文档,基本上只需要返回length(_id_1)
根据定义,聚合不以这种方式工作。除非有一个匹配阶段实际上排除了一个文档,否则每个文档 * 都是从“磁盘”*(MongoDB自己的缓存和FS缓存暂时放在一边)读取的,以便进一步处理。

wmomyfyw

wmomyfyw2#

我遇到了同样的问题,我只是希望任何人都可能有一个更好的答案,然后什么是以前张贴。
我有一个“用户”集合,其中有1200万用户,使用MongoDB 5.0。
我的查询看起来像这样:

db.users.aggregate([
  { '$sort': { updated_at: -1 } },
  { '$facet': { 
      results: [      
          { $skip: 0 },
          { $limit: 20 }
      ], 
      total: [
          { $count: 'count' }
      ] 
    } 
  }
])

查询需要大约1分钟,因此这是不可接受的。
我有一个关于“updated_at”的索引,这不是问题所在。
此外,即使我直接在Compass中的MongoShell上运行它,我也会遇到这个问题。因此,它与之前怀疑的任何NodeJs Mongo驱动程序无关。
我可以告诉Mongo使用估计的计数吗?或者有没有其他方法来改进查询?

axr492tv

axr492tv3#

@mustordont,你是对的,根本不要使用$facet。我刚刚从生产查询中删除了所有$facet。改进后的查询时间从6s缩短到1 ms(200万条记录)

相关问题