【问题标题】:Mongodb Aggregation slow count using facetMongodb聚合慢计数使用方面
【发布时间】:2019-06-05 07:40:21
【问题描述】:

我想使用一个方面来创建一个简单的查询,我可以使用它来获取分页数据,但是我注意到如果我这样做,与只运行两个单独的查询相比,我的性能真的很差。

作为一个快速测试,我创建了一个包含 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);

这样做的结果是两个单独的查询一个用于查找另一个用于计数大约需要 2 毫秒,而聚合单个查询需要 500 毫秒。 p>

为什么聚合这么慢?

更新

即使只是在聚合中没有分面的计数也很慢

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() 方法使用聚合而不是计数方法发现就像我上面的示例一样,它的性能明显更差,以至于我将继续使用已弃用的方法而不是较新的 countDocuments() 方法。

【问题讨论】:

  • 删除第一个$match阶段并使用$count查询而不是$group....aggregate([ { "$facet" : { "data": [ { "$skip": 0 }, { "$limit": 10 } ], "pageInfo": [ { $count:"count" } ] }} ])
  • @AnthonyWinzlet 它是专门格式化的,因为我有一个复杂的 $match 这是一个显示问题的简化示例。这就是聚合中的计数很慢。

标签: mongodb aggregation-framework


【解决方案1】:

当然很慢。 count() 方法只是在查询应用后返回游标大小(这并不一定需要读取所有文档,具体取决于您的查询和索引)。此外,对于空查询,查询优化器知道应该返回所有文档,基本上只需要返回length(_id_1)

根据定义,聚合不是这样工作的。除非存在实际排除文档的匹配阶段,否则每个文档都会从“磁盘”(MongoDB 自己的缓存和 FS 缓存暂不考虑)读取以进行进一步处理。

【讨论】:

  • 如果是这种情况,为什么 NodeJS 驱动程序会贬低 .Count() 方法,转而使用依赖于底层聚合的方法,它会在各处破坏性能。跨度>
  • @Daxxy 也许是因为of the bug SERVER-3645?这位谦虚的评论者发现您可以使用聚合获得正确的结果。然而,这个错误在 3.7.4 中被修复了......也许是因为 3.4 和 3.6 的支持?建议进一步阅读:Aggregation Pipeline Behaviordb.collection.count()
  • @Markus 你知道有没有关于这个的官方文档?我基本上遇到了同样的事情,正在寻找解释它的文档,但没有找到任何东西。
  • @alexvy86 实际上,上面评论中的 count 文档解释了它的行为。至于聚合:early filtering 的描述描述了当且仅当在管道的开头有一个$match 阶段时,才访问一个子集。这意味着如果您不将管道限制为集合的子集,则可以访问集合中的所有文档。
  • 啊,在Index use 部分找到它,你是对的: > 但是,如果查询可以使用索引但查询谓词不访问单个连续范围的索引键或查询还包含索引外字段的条件,那么除了使用索引之外,MongoDB 还必须读取文档以返回计数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-25
  • 2019-05-28
  • 1970-01-01
  • 1970-01-01
  • 2012-10-11
相关资源
最近更新 更多