【问题标题】:Running MongoDB aggregations in parallel并行运行 MongoDB 聚合
【发布时间】:2015-06-04 19:45:35
【问题描述】:

目前我正在针对包含用户和事件信息的集合运行聚合。例如:

[
  {
    $match: {
      client: ObjectId('507f1f77bcf86cd799439011'),
      location: 'UK'
    }
  },
  {
    $group: {
      _id: null,
      count: {
        $sum: 1
      }
    }
  }
]

上面是一个很大的简化,可以说有大约 20 个不同的变量,比如 location 可以进入 $match 语句。这两者之间有时还会有额外的步骤,这就是我使用$group 进行计数的原因。 (而不是count)

目前我在client 字段上有一个索引,但还没有在其他字段上创建索引(复合或其他)。由于还有很多其他字段,我不能只为所有内容创建索引 - 这太昂贵了。

问题:这在客户拥有少量文档时非常有用,但随着数量的增长,聚合必须扫描越来越多的文档。索引将范围向下聚焦,但这还不够。


想法

创建一个名为p(用于分区)的附加变量,并创建一个复合索引:{ client: 1, p: 1 }。 p 可以是1-n。

不要运行上面的管道,而是运行类似的管道n 次:(对于p 的所有可能值)

[
  {
    $match: {
      client: ObjectId('507f1f77bcf86cd799439011'),
      p: 1, // or 2, 3, etc
      location: 'UK'
    }
  },
  {
    $group: {
      _id: null,
      count: {
        $sum: 1
      }
    }
  }
]

然后可以在应用程序级别合并来自所有管道的结果。

使用这种方法,我可以限制每个查询必须执行的扫描次数,理论上可以减少查询时间。

更进一步,p 值可以用作分片键,因此理论上,分析查询可以跨多个分片并行运行。

以前有人做过这样的事吗?我在这个主题上发现的很少。

【问题讨论】:

  • 你说这是一个简化的例子。它的最终目标是给你一个计数吗?如果不是,目标是什么?我不认为运行相同的查询n 次将是一条好路线。调整管道可能会更好。
  • 目标可能是获取计数、文档列表或运行进一步的聚合步骤来总结特定字段。可以进入 $match 步骤的变量因用户输入而异,但我无法为所有变量创建索引 - 管道已经调整。考虑到这一点,现在运行 n 次查询是一条好路吗?如果不是,为什么?
  • 使用应用程序逻辑来强制执行数据库之外的性能,您创建的方法是不可扩展的。当数据库增长更多时会发生什么?添加更多ps。最终你会陷入同样的​​境地。我询问最终目标的原因是也许……聚合不是这项工作的正确工具,也许是。上面的例子可以用 .count(query) 来解决。如果您传递的领域比需要的多,Mongo 会变慢。例如 500k 文档上的 collection.find({},{_id:1}) 将立即返回,因为它不会尝试检索完整文档。
  • 同意 - 上面的答案可以用count 解决,也许我应该坚持这一点而不是使用管道(即使这是我们正在使用的)。随着数据库的增长,添加更多ps 正是我想要做的,是的。这显然不会无限期地工作,但我看不到我们很快就会使用超过 20 个ps。考虑到这一点,每个单独的查询都会更快,因此整体“查询”将是,不是吗?
  • 我个人不这么认为。但是您可以做的是运行测试并在查询结束时抛出.explain("executionStats"),您将获得性能统计信息。如果查询 mils * 20 p 加上任何你需要组合的结果是合理的,那么你应该是好的。

标签: mongodb


【解决方案1】:

对这种方法的早期测试表明它真的非常好。并行运行多个count查询意味着“总查询时间”计算现在是:

total time = max(single query time) + combination time

我还没有在大范围内测试过这个,但在中等范围内,这绝对是一种享受。

关于此测试的简要统计数据:

  • 集合有 250 万份文档
  • 这些文档中有 200k 具有我关心的 client 参数
  • 我正在并行运行 4 个查询,每个查询都查看不同的文档子集 (~50k)

对于少量扫描,这种方法几乎没有任何好处。然而对于上面的例子,我们得到total time 减少了 2-4x。

看起来这种方法在 50-100k 子集大小之间有一个最佳点。

当然,并行运行大量查询会使您可能受到其他 MongoDB 限制。

【讨论】:

    猜你喜欢
    • 2017-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多