【问题标题】:MongoDB: What is the effect of document size on collection scan performance and "working set" memory footprint?MongoDB:文档大小对集合扫描性能和“工作集”内存占用有什么影响?
【发布时间】:2019-11-06 02:42:19
【问题描述】:

我正在考虑将“相当大”的文档集合拆分为 2 个集合(通常是查询汇总字段,从不查询详细字段/文档数组)。目的是减少平均文档大小,从而减少“工作集”内存占用和集合扫描时间。文档将从 ~9.5kB 减少到 ~2.7kB,减少 3.5 倍(内存 BSON 大小)。

这应该会减少对 WiredTiger 缓存的要求,减少相同的 3.5 倍,因此需要减少 3.5 倍的机器内存。它还会以类似的速度加快收集扫描查询的速度吗?更新/插入操作很少见且对性能不重要,因为在离线批处理中运行。

这适用于在 FreeBSD 上运行的 MongoDB 4。 Web 应用程序在 php7.3 中,但这并不重要。

我目前有 100 万份以上大小的文档。解压后大约有 3.5GB 的磁盘空间和 7GB 的内存空间。当前服务器有 16GB RAM,但这已成为一个问题,也是动机的一部分,因为文档数量预计将快速增长到 400 万,然后缓慢增长到 800 万。

该应用程序主要是一个“切片和骰子”查询界面。 UI 中大约有 20 个不同的“过滤器”在各种汇总字段上驱动查询条件。它们都被索引了,包括一些复合索引和一些用于小数组的多键,但是因为“UI过滤器”可以在任何组合中使用,索引并不总是有帮助,因为为每个可能的字段组合创建复合索引是不现实的.

集合文档的结构是 5 个大的详细子文档数组(它们占总文档大小的约 70%),加上一些计算的“摘要字段”。汇总字段是在一个缓慢的离线过程中从大量详细的子文档中计算出来的。这很好,不是问题。查询仅针对汇总字段,而不针对原始子文档。但我们最终会得到定期的“完整收藏扫描”。随着集合规模的增长,这些开始放缓。目前大约 10 秒,没有可用的索引,结果几乎包括完整的集合。这太慢了,无法真正互动。计数对应用程序至关重要,而且它们通常需要完整的集合扫描。我们已经通过“涵盖的查询”(包括计数)做了我们可以做的事情。

建议将原始详细子文档存储在由_id“链接”的单独集合中。永远不需要“查找连接”,除非在时间不严格的后台批处理期间。更新极为罕见。

我们分析了由原始子文档组成的集合的比例,并将它们移到单独的(且很少访问)集合中,平均文档大小将减少 3.5 倍。

我们预计这将减少wiredTiger 缓存大小要求相同的因素,从而降低我们的物理硬件RAM 扩展要求。

问题是:当需要收集扫描时,我们是否还会看到查询执行时间的减少,因为 CPU 只扫描更轻量级的文档?这里的任何增益是否会有类似的数量级,即~3.5x?

或者这是一个错误的希望,因为 BSON 结构允许 WiredTiger 跳过每个文档中的所有“死木”。如果是这种情况,由于芯片缓存中的 CPU 可能仍然会有较小的增益?即较小的文档将在连续内存中更多?

【问题讨论】:

  • 较小的文档绝对会导致加速。因为在同一空间中有更多的它们(内存页面、磁盘扇区等)。它们越紧凑,需要的存储读取就越少(缓存访问仍然比不访问慢)。至于幅度,当然需要衡量。
  • @SergioTulentsev 谢谢。这是对我想法的令人鼓舞的验证。

标签: mongodb mongodb-query


【解决方案1】:

现在完成了这个集合拆分。结果很好:

  • mongod 的内存占用按预期减少了约 3.4 倍
  • 集合扫描速度也显着加快(约 3 倍)

因此,如果您有一个大型集合(许多文档),由于子数组/文档很大,平均文档大小很大,并且查询很少需要这些子数组/文档(即不需要太多 $lookups 或类似),然后将它们分成单独的集合可能非常值得。

较低的 RAM 要求和更快的集合扫描大致是您设法减少平均文档大小的因素。

【讨论】:

    猜你喜欢
    • 2016-01-25
    • 2013-09-20
    • 2014-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-08
    相关资源
    最近更新 更多