首页 文章

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

提问于
浏览
17

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

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

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

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

Question: is this even a problem in MongoDB? Does document size even matter if your queries are properly managed using projection and indexes, etc? Should we be actively pruning document size, e.g. with references to external lists vs. embedding lists of _id values directly?

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

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

2 回答

  • 13

    重新解释这个问题的一种方法是,如果文件是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-limit

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

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

    希望这可以帮助!

  • 6

    首先,您应花一点时间阅读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%的不需要的用户文档上浪费大量存储,但代价是额外的应用程序复杂性 .

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

    覆盖查询是一种查询,其中:查询中的所有字段都是索引的一部分,和
    结果中返回的所有字段都在同一索引中 .
    因为索引“覆盖”了查询,所以MongoDB可以匹配查询条件并仅使用索引返回结果; MongoDB不需要查看文档,只需查看索引即可完成查询 . 仅查询索引比查询索引之外的文档要快得多 . 索引键通常小于它们编目的文档,索引通常可在RAM中使用或按顺序位于磁盘上 .

    关于这种方法的更多信息:http://docs.mongodb.org/manual/tutorial/create-indexes-to-support-queries/

相关问题