MongoDB:文档大小会影响查询性能吗?

tob*_*pwn 25 mongodb mongodb-query

假设一个由MongoDB数据库支持的移动游戏,该数据库包含User具有数百万个文档的集合.

现在假设必须与用户关联的几十个属性 - 例如文档的_id值数组Friend,用户名,照片,文档_id值的数组Game,last_login日期,游戏内货币的数量等等.

我担心的是,在数百万个用户文档上创建和更新大型增长数组是否会给每个用户文档增加任何"权重",和/或整个系统的速度变慢.

我们可能永远不会超过每个文档16mb,但我们可以肯定地说,如果我们直接存储这些增长列表,我们的文档将增加10-20倍.

问题:这是MongoDB中的一个问题吗?如果使用投影和索引等正确管理您的查询,文档大小是否重要?我们是否应该主动修剪文档大小,例如引用外部列表与_id直接嵌入值列表?

换句话说:如果我想要一个用户的last_login值,last_login如果我的User文件是100kb而不是5mb,那么只投射/选择该字段的查询是否会有所不同?

或者:如果我想查找具有特定last_login值的所有用户,文档大小是否会影响该类查询?

Joh*_*one 15

首先,您应花一点时间阅读MongoDB如何参考填充因子和powerof2sizes分配来存储文档:

http://docs.mongodb.org/manual/core/storage/ http://docs.mongodb.org/manual/reference/command/collStats/#collStats.paddingFactor

简单地说,MongoDB尝试在存储原始文档时分配一些额外的空间以允许增长.Powerof2sizes分配成为2.6版本中的默认方法,它将以2的幂增长文档大小.

总的来说,如果所有更新都符合原始大小分配,性能会更好.原因是,如果他们不这样做,整个文档需要在其他地方移动,并留有足够的空间,从而导致更多的读写操作,从而实际上破坏了存储.

如果您的文档的大小实际上会增加10倍到20倍的加班时间,这可能意味着每个文档有多次移动,这取决于您的插入,更新和读取频率可能会导致问题.如果是这种情况,您可以考虑以下几种方法:

1)在初始插入时分配足够的空间以覆盖正常文档生命周期增长的大部分(假设90%).虽然这在开始时的空间使用效率低下,但随着文档的增长,效率将随着时间的推移而增加而不会降低性能.实际上,您将提前支付存储费用,以便稍后使用以获得良好的性能.

2)创建"溢出"文档 - 假设一个典型的80-20规则适用,80%的文档适合一定的大小.如果他们有超过100个朋友或100个游戏文档,则为该数量分配并添加文档可指向的溢出集合.溢出字段指向此新集合中的文档,如果存在溢出字段,则应用程序仅查找新集合.允许80%的用户进行正常的文档处理,并避免在80%的不需要的用户文档上浪费大量存储,但代价是额外的应用程序复杂性.

在任何一种情况下,我都会考虑通过构建适当的索引来使用覆盖的查询:

覆盖查询是一种查询,其中:

all the fields in the query are part of an index, and
all the fields returned in the results are in the same index.
Run Code Online (Sandbox Code Playgroud)

因为索引"覆盖"了查询,所以MongoDB可以匹配查询条件并仅使用索引返回结果; MongoDB不需要查看文档,只需查看索引即可完成查询.

仅查询索引比查询索引之外的文档要快得多.索引键通常小于它们编目的文档,索引通常可在RAM中使用或按顺序位于磁盘上.

有关该方法的更多信息,请访问:http://docs.mongodb.org/manual/tutorial/create-indexes-to-support-queries/

  • 这个答案本身是正确的,但并没有真正回答这个特定的问题。我想知道为什么这是一个公认的答案。 (3认同)
  • 您的文档对我来说听起来并不大 - 请记住限制是 16 MB,除非我遗漏了一些您将远低于 16 KB 的内容,因此您不必担心文档大小。大多数人不会太担心文档大小。通过嵌入的 _id 值引用外部集合会显着增加查询成本(两个而不是一个),因此您只在必须时才这样做。综上所述,我可以为您提供关于 MongoDB 的最佳建议是对其进行基准测试。每个用例都略有不同。 (2认同)

小智 11

重新解释这个问题的一种方法是,如果文档是16mb而不是16kb,则100万文档查询需要更长时间.

如果我错了,请纠正我,根据我自己的经验,文档大小越小,查询越快.

我已经对500k文档和25k文档进行了查询,25k查询明显更快 - 范围从几毫秒到1-3秒更快.在生产时,时差约为2倍-10倍.

文档大小发挥作用的一个方面是查询排序,在这种情况下,文档大小将影响查询本身是否运行.我已经多次达到这个限制,尝试排序2k文件.

这里有一些解决方案的更多参考资料:https : //docs.mongodb.org/manual/reference/limits/#operations https://docs.mongodb.org/manual/reference/operator/aggregation/sort/#sort-memory-限制

在一天结束时,它的最终用户会受到影响.

当我尝试修复大型查询导致无法接受的缓慢性能时.我经常发现自己创建了一个包含数据子集的新集合,并使用了大量的查询条件以及排序和限制.

希望这可以帮助!


bru*_*nde 8

只是想分享我在 MongoDB 中处理大型文档时的经验...不要这样做!

我们犯了一个错误,允许用户在文档中包含以 Base64 编码的文件(通常是图像和屏幕截图)。我们最终收集了大约 50 万个文档,每个文档大小从 2 Mb 到 10 Mb 不等。

在此集合中进行简单聚合会导致集群崩溃!

MongoDB 中的聚合查询可能非常繁重,尤其是对于像这样的大型文档。聚合中的索引只能在某些情况下使用,并且由于我们需要$group,因此未使用索引,并且 MongoDB 必须扫描所有文档。

在具有较小文档的集合中执行完全相同的查询执行速度非常快,并且资源消耗不是很高。

因此,在 MongoDB 中查询大型文档会对性能产生很大影响,尤其是聚合。

另外,如果您知道文档在创建后将继续增长(例如,在给定实体(文档)中包含日志事件),请考虑为这些子项创建一个集合,因为大小将来也可能成为问题。

布鲁诺。