了解MongoDB BSON文档大小限制


153

来自MongoDB权威指南:

大于4MB的文档(转换为BSON时)无法保存到数据库。这是一个任意的限制(将来可能会提高);这主要是为了防止不良的架构设计并确保一致的性能。

我不了解此限制,这是否意味着包含博客帖子且带有大量评论且恰好大于4MB的文档不能存储为单个文档?

这也算嵌套文档吗?

如果我想要一个审核值更改的文档怎么办?(它最终可能会增长,超过4MB的限制。)

希望有人能正确解释。

我刚刚开始阅读有关MongoDB(我正在学习的第一个nosql数据库)的信息。

谢谢。


5
我认为这个问题应该阐明这是对MongoDB存储文档大小的限制,而不是BSON格式的限制。
alexpopescu 2011年

2
但是,我只是尝试保存一个肯定超过4MB的巨大文档,以获取消息“ BSON :: InvalidDocument:文档太大:BSON文档限制为4194304字节”。如果是这样,在警告/错误消息中难道不会引起误解吗?
Nik So

18
您可以使用Shell中的db.isMaster().maxBsonObjectSize/(1024*1024)+' MB'命令轻松找到最大BSON文档大小mongo
AhmetB-Google 2011年

5
无模式nosql的目的是什么,即您不能转储超过16 mb的记录并在其之上构建crud操作!
Rizwan Patel

我认为最初的报价说明了一切...为了防止不良的架构设计,已经设置了限制。例如,如果您的帖子中包含很多评论,则需要博客条目集合和评论集合,或更改集合。mongo / nosql的设计允许将大型事物作为文档网络,但是开发人员需要将它们分解为有意义的部分。如果未设置大小限制,则会发生其他问题。我认为4mb的限制还可以。16mb,太好了!但是,如果我正在编写一个16mb的文档,则可以说明设计存在其他问题。
睫毛

Answers:


126

首先,这实际上是在8MB16MB... 的下一个版本中提出的,但我认为,从10gen(开发MongoDB的人)的艾略特(Eliot)的观点来看,它是最好的:

编辑: 大小已正式 “提高”到16MB

因此,在您的博客示例中,4MB实际上是很多。.例如,“世界大战”的全部未压缩文本仅为364k(html):http : //www.gutenberg.org/etext/36

如果您的博客文章有这么多评论那么长,我将一本不读:)

对于引用,如果您为它们分配了1MB的空间,则很容易超过10k(可能接近20k)

因此,除了真正奇怪的情况外,它都将很好地工作。而且在例外情况或垃圾邮件中,我真的不认为您还是想要20mb的对象。我认为将引用限制在15k左右是很有意义的,无论性能如何。或至少有特殊情况下使用。

-艾略特

我认为要达到极限非常困难……随着时间的流逝,如果升级……您将越来越不必担心。

限制的要点是,这样就不会用完服务器上的所有RAM(因为MB查询时需要将所有文档加载到RAM中。)

因此,限制是普通系统上正常可用RAM的一定百分比...这将保持逐年增长的趋势。

在MongoDB中存储文件的注意事项

如果您需要存储的文档(或文件)大于16MB您可以使用的GridFS API,它将自动将数据分解成段并将其流式传输回给您(从而避免了大小限制/ RAM的问题)。

GridFS不会将文件存储在单个文档中,而是将文件分为多个部分或大块,并将每个大块存储为单独的文档。

GridFS使用两个集合来存储文件。一个集合存储文件块,另一个集合存储文件元数据。

您可以使用此方法在数据库中存储图像,文件,视频等,就像在SQL数据库中一样。我用它甚至可以存储多GB的视频文件。


2
太棒了,您有足够的RAM用于整个数据库...通常,“工作集”位于RAM中,而不是整个数据库中(例如,在我的情况下,我有多个GB GB的数据库,如果全部加起来,它们将超过我的RAM,但这没关系,因为工作集要小得多。)此外,如果没有限制,则可以将800MB的文档加载到带有一个查询的RAM中,将40万个文档加载到另一个查询中,从而使RAM平衡变得有些困难,等等。因此,“限制”是典型服务器RAM的某些百分比(因此,它会随着时间而增长。) mongodb.org/display/DOCS/Checking+Server+Memory+Usage
Justin Jenkins

3
您可以将所有内容存储在RAM中,但要考虑效率和博客文章成语,这是很棒的。您显然希望帖子被读入内存。但是,当大多数人永远不会阅读超过第一页的内容时,您是否真的真的想在博客文章中留下10页的评论?当然,您可以这样做,并且如果您的数据库足够小,可以全部容纳在内存中,那么就没问题。但是就纯粹的效率而言,如果可以避免的话,您不希望无用的位占用内存空间(对于RDBMS也是这样)。
AlexGad 2011年

50
甜蜜的耶稣,所以Mongo的论据是“ 16 MB对任何人都应该足够”?过去从来没有那样证明过它是错误的。
罗伯特·

2
这对我来说似乎太糟糕了。Mongo被认为对大数据很有用,没有这样的限制。在我的项目中,我需要汇总和分组与同一趋势主题相关的推文,这可能会在20个小时的时间内导致超过20000条推文(而且很可能趋势会持续超过在我的数据库中20个小时)。拥有那么多推文并同时存储其文本是毁灭性的,并且在将一些小趋势归为一组之后,最终却出现了大趋势。
Savvas Parastatidis

7
@savvas为什么将所有推文放在一个文档中?每条推文使用一个文档,将趋势主题作为文档中的另一个字段。在该主题字段上放置一个索引,然后使用mongo管道在该字段上进行汇总。一旦调整了方法并认为您会发现它适用于许多大数据用例,就需要对使用nosql的工作方式进行一些调整。
schmidlop

32

社区中的许多人都希望对性能的警告不加限制,有关合理的论点请参见此评论:https : //jira.mongodb.org/browse/SERVER-431? focusedCommentId = 22283 & page =com.atlassian.jira.plugin。 system.issuetabpanels:comment-tabpanel#comment-22283

我认为,主要开发人员对这个问题s之以鼻,因为他们认为早期它是重要的“功能”。他们不会很快更改它,因为有人质疑它的感觉会伤害他们。在开放源代码社区中,个性和政治削弱产品的另一个例子,但这并不是一个严重的问题。


5
我完全同意您的观点,这也违反了现在拥有嵌入式文档的目的,因为大多数嵌入式文档现在都可以轻松越过极限。ESP与内部的单据阵列
Sharjeel艾哈迈德

@ marr75它说现在已修复,是否已修复?
Mafii '16

1
我的意思是,该限制已提高到16MB,无法解决长期的“问题”;IMO的限制应该被取消。
marr75 '16

2
6岁的线程坏死。对于您的特定不良用例/设计示例,我坚信不服。同样,该示例比说明数据库单文档大小限制更好地说明了为什么您需要验证输入。使应用程序将其嵌套的文档拆分为另一个集合中的单个文档,或启动一个新的“继续”文档(我已在此限制内使用过多次的解决方案)对性能的影响很小,但对代码复杂性的影响却很大。文档数据库的重点是数据局部性。
marr75

4
感谢mongoDB文档为捍卫这一决定所做的相同的数学运算,但是您的单个用例和思想实验远没有定论。我不得不想出复杂的冗余设计来解决以下事实:mongo确实会受到任意限制(没有深层嵌套或重复的条目,顺便说一句)。根据您的逻辑,任何数据库都不应包含超过16MB的总容量,因为可以使用较少的存储空间来表示任意文本。这显然是愚蠢的。
marr75

31

要在此处为​​那些由Google指导的人提供澄清的答案。

文档大小包括文档中的所有内容,包括子文档,嵌套对象等。

因此,一个文件:

{
    _id:{},
    na: [1,2,3],
    naa: [
        {w:1,v:2,b:[1,2,3]},
        {w:5,b:2,h:[{d:5,g:7},{}]}
    ]
}

最大大小为16兆。

Sbudocument和嵌套对象都计入文档的大小。


具有讽刺意味的是,能够用BSON表示的最大的单一结构也是最紧凑的。尽管MongoDB在内部使用size_t(64位)数组索引,但是16MB的文档大小限制最多只能表示一个包含单个数组本身的文档,该数组本身包含200万个NULL。
amcgregor

抱歉,添加第二条评论来解决/阐明另一个重要的细节:当您说文档大小包括文档中的所有内容时,还包括。例如,{"f": 1}比少两个字节{"foo": 1}。如果您不小心的话,这很快就会加起来,尽管现代的磁盘压缩确实有帮助。
amcgregor

6

我还没有看到限制的问题,该限制不涉及文档本身中存储的大文件。已经存在各种各样的数据库,它们在存储/检索大文件方面非常有效;它们被称为操作系统。数据库作为操作系统上的一层存在。如果出于性能原因使用NoSQL解决方案,为什么要通过在应用程序和数据之间放置数据库层来增加数据访问的额外处理开销?

JSON是一种文本格式。因此,如果您要通过JSON访问数据,则在拥有二进制文件的情况下尤其如此,因为二进制文件必须以uuencode,十六进制或Base 64进行编码。转换路径可能类似于

二进制文件<> JSON(已编码)<> BSON(已编码)

将路径(URL)放在文档中的数据文件中,并将数据本身保存为二进制,会更有效。

如果您确实想将这些未知长度的文件保留在数据库中,那么最好将它们放在GridFS中,并且不存在在访问大文件时冒并发性的风险。


1
“已经有各种各样的数据库在存储/检索大文件方面非常有效;它们被称为操作系统。” 见blog.mongodb.org/post/183689081/...
redcalx


2

也许将博客文章->评论关系存储在非关系数据库中并不是最好的设计。

无论如何,您可能应该将评论存储在单独的集合中,以撰写博客文章。

[编辑]

请参阅下面的评论以进行进一步讨论。


15
我完全不同意。您的博客文章文档中的注释在MongoDB中应该是完美的……这是一种非常普遍的用法(我在生产环境中多次使用它,并且效果很好。)
Justin Jenkins

2
我的回答也许过于严格。将博客文章和相关评论存储在MongoDB或类似数据库中没有错。人们倾向于过度使用基于文档的数据库所提供的功能(最根本的例子是将所有数据存储在一个名为“博客”的文档中)
Mchl 2011年

3
@Mchel:“博客”并不好,但是出于相同的原因,将评论存储在单独的集合中也同样糟糕。带有注释数组的帖子就像文档数据库的典型示例。
Matt Briggs

6
@SoPeople:在帖子中存储评论就像面向文档的数据库的典型示例。(例如将整个Wiki文本存储在一个文档中)如果我要编写SO,它将完全在MongoDB上运行。这些SO条目都不会合理地超过4MB。Craigslist正在将他们的历史数据库迁移到MongoDB。他们只有几个文档超过了该限制,并且主要开发人员建议文档本身实际上已被破坏(某些错误的结果)。同样,4兆是几本文本小说。
盖茨副总裁,

3
@Gates副总裁,我同意使用单独的全文本引擎。我在考虑元数据搜索。如果您有一组Book文档,并且想要查找1982年出版的所有图书,该怎么办?如果每本书都有+ 100kb的文字,则您不希望仅显示前20个书名就传输几兆字节。
mikerobi 2011年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.