【问题标题】:Understanding MongoDB BSON Document size limit了解 MongoDB BSON 文档大小限制
【发布时间】:2023-03-28 23:13:01
【问题描述】:

来自 MongoDB 权威指南:

大于 4MB 的文档(转换为 BSON 时)不能 保存到数据库中。这是一个有点武断的限制(并且可能是 未来提出);主要是为了防止糟糕的架构设计并确保 一致的表现。

我不明白这个限制,这是否意味着包含大量 cmets 且恰好大于 4MB 的博客文章的文档不能存储为单个文档?

这也算嵌套文档吗?

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

希望有人正确解释这一点。

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

谢谢。

【问题讨论】:

  • 我认为问题应该澄清,这是 MongoDB 存储文档大小的限制,而不是 BSON 格式的限制。
  • 不过,我只是尝试保存一个肯定超过 4MB 的巨大文档,以获取消息“BSON::InvalidDocument:文档太大:BSON 文档限制为 4194304 字节。”如果是这种情况,在警告/错误消息中是不是有点误导?
  • 您可以在mongo shell 中使用db.isMaster().maxBsonObjectSize/(1024*1024)+' MB' 命令轻松找到您的最大 BSON 文档大小。
  • 无模式 nosql 的目的是什么,您不能转储超过 16 mb 的记录并在其上构建 crud 操作!
  • 我认为最初的报价说明了一切......限制是为了防止糟糕的架构设计。例如,如果您有一个包含许多 cmets 的帖子,您会想要一个博客条目集合和一个评论集合,或者一个更改集合。 mongo/nosql 的设计允许将大型事物作为文档网络,但开发人员需要将它们分解成有意义的部分。如果没有设置大小限制,就会出现其他问题。我认为 4mb 的限制很好。 16mb,太棒了!但是,如果我正在编写一个 16mb 的文档,那就是设计存在其他问题的线索。

标签: mongodb bson


【解决方案1】:

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

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

[编辑]

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

【讨论】:

  • 我完全不同意。您的博客文章文档中的评论在 MongoDB 中应该非常好……这是一种非常常见的用途(我在生产中不止一个地方使用它,而且效果很好。)
  • 我的回答可能过于严格。在 MongoDB 或类似数据库中存储博客文章和关联的 cmets 没有任何问题。更多的是人们倾向于过度使用基于文档的数据库提供的功能(最激进的例子是将所有数据存储在一个名为“博客”的文档中)
  • @Mchel:“博客”不好,但出于同样的原因,将 cmets 存储在单独的集合中同样糟糕。带有 cmets 数组的帖子就像是文档数据库的规范示例。
  • @SoPeople:在帖子中存储 cmets 就像面向文档的数据库的典型示例。 (就像将整个 wiki 文本存储在一个文档中)如果我要编写 SO,它将完全在 MongoDB 上运行。这些 SO 条目都不会合理地超过 4MB。 Craigslist 正在将他们的历史数据库迁移到 MongoDB。他们只有几个文档超过了这个限制,而首席开发人员建议文档本身实际上被破坏了(一些错误的结果)。同样,4 megs 是几本文字小说。
  • @Gates VP,我同意使用单独的全文引擎。我在考虑元数据搜索。如果您有一组 Book 文档,并且想要查找 1982 年出版的所有书籍,该怎么办?如果每本书都有 +100kb 的文本,您不想传输几兆字节只是为了显示前 20 个书名。
【解决方案2】:

首先,这实际上在下一个版本中被提升为 8MB16MB ...但我认为从这个角度来看,来自 10gen(开发 MongoDB)的 Eliot 说得最好:

编辑: 尺寸已被officially“提升”为16MB

因此,在您的博客示例中,4MB 是 实际上很多..例如, “战争之战”的完整解压缩文本 世界”只有 364k (html): http://www.gutenberg.org/etext/36

如果你的博客文章那么长 那么多cmets,我一个都不是 要去读它:)

对于引用,如果您专用 1MB 对他们来说,你可以轻松拥有更多 超过 10k(可能接近 20k)

所以除了真的很奇怪 情况下,它会很好用。而在 例外情况还是垃圾邮件,我真的 不要认为你想要一个 20mb 的对象 反正。我认为将引用限制为 15k左右很有意义 不管性能如何。或 最不特殊的外壳,如果有的话 发生。

-艾略特

我认为你很难达到极限......随着时间的推移,如果你升级......你会越来越少担心。

限制的要点是不要用完服务器上的所有 RAM(因为您需要在查询时将文档的所有 MBs 加载到 RAM 中。 )

所以限制是通用系统上正常可用 RAM 的一些百分比......这将逐年增长。

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

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

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

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

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

【讨论】:

  • 太棒了,你有足够的 RAM 用于整个数据库......通常“工作集”在 RAM 中,而不是整个数据库(比如在我的情况下,我有超过一个 x GBs 的数据库,如果所有加起来都会超过我的 RAM,但这没关系,因为工作集要小得多。)此外,如果没有限制,您可以将一个 800MB 的文档加载到 RAM 中,一个查询和一个 400k 的文档与另一个查询,进行平衡你的 RAM 有点困难,等等。所以“限制”是典型服务器 RAM 的一些百分比(因此它会随着时间的推移而增长。)mongodb.org/display/DOCS/Checking+Server+Memory+Usage
  • 可以将所有内容存储在 RAM 中真是太好了,但要考虑效率和博客文章的成语。您显然希望帖子在阅读后能在内存中。但是,当大多数人永远不会读过第一页时,您真的希望 10 页的 cmets 能够在内存中存储吗?当然,您可以做到,如果您的数据库足够小,可以全部放入内存,那么没问题。但就纯粹的效率而言,如果可以避免无用位占用内存空间,您不希望它占用内存空间(RDBMS 也是如此)。
  • 亲爱的耶稣,所以 Mongo 的论点是“16 MB 应该对任何人都足够”?在过去,它并不是这样被证明是不正确的。
  • 这对我来说似乎太糟糕了。 Mongo 应该对大数据有用,没有这样的限制。在我的项目中,我需要汇总和分组与同一趋势主题相关的推文,这可能会在 20 小时的时间段内产生超过 20000 条推文(而且很可能会有持续时间超过在我的数据库中 20 小时)。拥有这么多推文并同时存储它们的文本是毁灭性的,在对一些小趋势进行分组之后,它最终会在大趋势上出现例外。
  • @savvas 为什么要将所有推文放在单个文档中?每条推文使用一个文档,将趋势主题作为文档的另一个字段。在该主题字段上放置一个索引,然后使用 mongo 管道在该字段上进行聚合。一旦你调整了你的方法并认为你会发现它适用于许多大数据用例,就需要对你如何使用 nosql 进行一些调整。
【解决方案3】:

社区中的许多人都希望在性能方面没有限制,请参阅此评论以获得合理的论点: https://jira.mongodb.org/browse/SERVER-431?focusedCommentId=22283&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-22283

我的看法是,主要开发人员对这个问题很固执,因为他们很早就认为这是一个重要的“功能”。他们不会很快改变它,因为任何人质疑它都会伤害他们的感情。另一个在开源社区中贬低产品的个性和政治示例,但这并不是一个严重的问题。

【讨论】:

  • 我完全同意你的观点,这也违背了现在嵌入文档的目的,因为大多数嵌入文档现在很容易越界。 Esp 里面有一系列文档
  • @marr75 现在说已修复,修复了吗?
  • 我的意思是,限制提高到 16MB,这并不能长期解决“问题”; IMO 应该取消限制。
  • 6 岁线程坏死。我对您特定的不良用例/设计示例深信不疑。此外,与数据库单个文档大小限制相比,该示例更能说明为什么需要验证输入。使应用程序将其嵌套文档拆分为另一个集合中的单个文档或启动一个新的“延续”文档(我已多次使用的解决方案在此限制内工作)对性​​能影响很小,但对代码复杂性影响很大。文档数据库的全部意义在于数据局部性。
  • 感谢您使用与 mongoDB 文档相同的数学方法来捍卫这一决定,但您的单一用例和思想实验远未得出结论。我不得不想出复杂的、冗余的设计来解决这样一个事实,即 mongo 确实会遇到任意限制(顺便说一句,没有深度嵌套或重复的条目)。根据您的逻辑,任何数据库都不需要包含超过 16MB 的总大小,因为可以使用更少的存储空间来表示一些任意文本。这显然很愚蠢。
【解决方案4】:

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

JSON 是一种文本格式。因此,如果您通过 JSON 访问您的数据,如果您有二进制文件尤其如此,因为它们必须以 uuencode、十六进制或 Base 64 进行编码。转换路径可能看起来像

二进制文件 JSON(编码) BSON(编码)

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

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

【讨论】:

【解决方案5】:

在这里为那些被 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 MB。

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

【讨论】:

  • 具有讽刺意味的是,能够在 BSON 中表示的最大可能结构也是最紧凑的。尽管 MongoDB 在内部使用 size_t(64 位)数组索引,但 16MB 文档大小限制最多只能表示包含单个数组的文档,该数组本身包含两百万个 NULL。
  • 道歉,添加第二条评论以解决/澄清另一个重要细节:当您说文档大小包括文档中的所有内容时,还包括。例如。 {"f": 1}{"foo": 1} 小两个字节。如果您不小心,这可能会迅速增加,但现代磁盘压缩确实有帮助。
【解决方案6】:

BSON 文档的嵌套深度: MongoDB 支持不超过 100 级的 BSON 文档嵌套。

More more info vist

【讨论】:

    【解决方案7】:

    根据https://www.mongodb.com/blog/post/6-rules-of-thumb-for-mongodb-schema-design-part-1

    如果您预计博客文章可能会超过 16Mb 文档限制,则应将 cmets 提取到单独的集合中,并从评论中引用博客文章并进行应用程序级联接。

    // posts
    [
      {
        _id: ObjectID('AAAA'),
        text: 'a post',
        ...
      }
    ]
    
    // comments
    [
      {
        text: 'a comment'
        post: ObjectID('AAAA')
      },
      {
        text: 'another comment'
        post: ObjectID('AAAA')
      }
    ]
    

    【讨论】:

      猜你喜欢
      • 2015-08-23
      • 2021-04-17
      • 2018-03-26
      • 2018-09-11
      • 1970-01-01
      • 2013-02-24
      • 1970-01-01
      • 2018-01-19
      相关资源
      最近更新 更多