当前位置: 首页 > 知识库问答 >
问题:

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

云建木
2023-03-14

假设一款手机游戏由一个MongoDB数据库支持,该数据库包含一个包含数百万文档的用户集合。

现在假设必须与用户关联的几十个属性-例如_id朋友文档的值数组、他们的用户名、照片、_id游戏文档的值数组、last_login日期、游戏内货币计数等,等等。

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

我们可能永远不会覆盖每个文档16mb,但我们可以有把握地说,如果我们直接存储这些不断增长的列表,我们的文档将大10-20倍。

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

换句话说:如果我想要一个用户的上次登录值,如果我的用户文档是100kb而不是5mb,那么只投影/选择上次登录字段的查询会有什么不同吗?

或者:如果我想找到具有特定上次登录值的所有用户,文档大小会影响这种查询吗?


共有3个答案

诸正谊
2023-03-14

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

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

在这个集合中进行简单聚合将导致集群崩溃!

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

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

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

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

布鲁诺。

陶璞
2023-03-14

首先,您应该花一点时间阅读MongoDB是如何根据填充因子和大小分配来存储文档的:

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.

由于索引“覆盖”了查询,MongoDB既可以匹配查询条件,也可以仅使用索引返回结果;MongoDB不需要查看文档,只需要查看索引即可完成查询。

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

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

松桐
2023-03-14

重新表述这个问题的一种方法是说,如果文档分别为16mb和16kb,100万文档查询是否需要更长的时间。

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

我对500k个文档和25k个文档进行了查询,25k个查询明显更快,从几毫秒到1-3秒不等。在生产中,时差约为2-10倍。

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

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

归根结底,受害的是最终用户。

当我试图纠正导致不可接受的性能缓慢的大型查询时。我通常发现自己使用数据子集创建一个新集合,并使用大量查询条件以及排序和限制。

希望这有帮助!

 类似资料:
  • 问题内容: 在浏览器中,缩小和隐藏或加载异步JavaScript会对性能产生积极影响。在Node.js中运行的代码是否也是如此? 如Example那样,过多的注释和为实例化的类的属性使用长名称通常会严重影响性能和内存使用吗? 问题答案: 是的 ,它可以提高编译时的性能,但是编译时对您的整个过程生命周期而言无关紧要,因此无关紧要。唯一的区别是,如果您出于某种奇怪的原因而不断地启动和停止节点程序,那么

  • 主要内容:find() 方法,pretty() 方法,findOne() 方法,条件查询,AND条件语句,OR 条件语句,AND 和 OR 联合使用前面我们介绍了怎么将文档插入到集合中,本节我们来介绍一下如何从集合中查询指定的文档。 find() 方法 想要查询集合中的文档,可以使用 MongoDB 中的 find() 方法,find() 方法可以将查询结果以非结构化的方式展示出来,其语法格式如下: db.collection_name.find(query, projection) 语法说明如

  • 我们的企业应用程序部署在Jboss Wildfly8.2中。jboss控制台日志是在启动过程中使用环境变量JBoss_Console设置的。这确保使用kill-quit触发的任何线程转储都转储到jboss_console.log。GC统计信息(使用-xx:+printgctimestamps-xx:+printgcdetails收集)也发送到此文件。 日志文件的旋转由 此外,du和ls命令的输出也

  • 我正在处理Azure Cosmos DB(通过. NET SDK)并注意到一些奇怪的事情。 通常,当我使用延续标记逐页请求查询时,我永远不会得到在第一个延续标记创建之后创建的文档。我可以观察到更改的文档,缺少删除的(或者说是新过滤掉的)文档,但是看不到新的文档。但是,如果我只允许1kB的延续标记(我能设置的最小标记),我也会得到新文档。显然,只要它们最终被排序到剩余的页面。 这有点道理,因为有了大

  • 是否可以在MongoDB中找到最大的文档大小? 显示的是平均大小,这并不具有代表性,因为在我的例子中,大小可能会有很大差异。

  • 我有一个只有2个文档的mongodb数据库。两者具有相同的结构: 小文档在消息中有0个对象,大文档有1000个。我数了数这两份文件上的标牌:小:28000大:450000 我使用nodeJS和常规mongodb驱动程序访问文档,并且我将索引设置为“general.sid”。 现在我要他们的将军提供文件。而且这两个文档的时间差别很大!我接收文档,进行一些计算并更新文档。 我打印接收和更新文档之前和之