Понимание MongoDB BSON Ограничение размера документа

153

От MongoDB Полное руководство:

Документы размером более 4 МБ (при преобразовании в BSON) не могут быть сохранены в базе данных. Это несколько произвольный предел (и может быть повышен в будущем); это в основном для предотвращения неправильного проектирования схемы и обеспечения стабильной производительности.

Я не понимаю этого ограничения. Означает ли это, что документ, содержащий сообщение в блоге с большим количеством комментариев размером более 4 МБ, не может быть сохранен как один документ?

Также учитывает ли это вложенные документы?

Что делать, если я хотел документ, который проверяет изменения стоимости. (В конечном итоге он может возрасти, превысив предел 4 МБ.)

Надеюсь, кто-то объясняет это правильно.

Я только начал читать о MongoDB (первая база данных nosql, о которой я узнаю).

Спасибо.

святой
источник
5
Я думаю, что вопрос должен прояснить, что это ограничение размеров хранимых документов MongoDB, а не формата BSON.
alexpopescu
2
Хотя я только что попытался сохранить огромный документ, который наверняка превышает 4 МБ, чтобы получить сообщение «BSON :: InvalidDocument: слишком большой документ: документы BSON ограничены 4194304 байтами». Если это так, разве это не вводит в заблуждение в предупреждении / сообщении об ошибке?
Ник Со
18
Вы можете легко найти ваш максимальный размер документа BSON с помощью db.isMaster().maxBsonObjectSize/(1024*1024)+' MB'команды в mongoоболочке.
AhmetB - Google
5
Какова цель nosql без схемы, где вы не можете записывать записи размером более 16 МБ и строить поверх него операции crud!
Ризван Патель
Я думаю, что первоначальная цитата говорит само за себя ... Ограничение установлено, чтобы предотвратить плохой дизайн схемы. Если, например, у вас есть сообщение с большим количеством комментариев, вам понадобится коллекция записей в блоге и коллекция комментариев или коллекция изменений. Конструкция mongo / nosql позволяет создавать объекты большого размера в виде сетей документов, но разработчику необходимо разбить их на части, которые имеют смысл. Если ограничение размера не установлено, возникнут другие проблемы. Я думаю, что ограничение 4 Мб было хорошо. 16 Мб, отлично! Но если я пишу документ размером 16 Мб, это признак того, что с дизайном что-то не так.
Ресницы

Ответы:

126

Во-первых, это на самом деле поднимается в следующей версии 8MBили 16MB... но я думаю, чтобы представить это в перспективе, Элиот из 10gen (который разработал MongoDB) считает это лучше:

РЕДАКТИРОВАТЬ: размер был официально "поднят" до16MB

Итак, в вашем примере с блогом, 4MB на самом деле очень много. Например, полный несжатый текст «Войны миров» составляет всего 364k (html): http://www.gutenberg.org/etext/36

Если ваш блог так долго с таким количеством комментариев, я, например, не буду его читать :)

Для трекбэков, если вы выделите им 1 МБ, вы можете легко получить более 10 КБ (возможно, ближе к 20 КБ).

Так что за исключением действительно странных ситуаций, это будет прекрасно работать. И в случае исключения или спама, я действительно не думаю, что вы все равно хотите объект 20 МБ. Я считаю, что ограничение трекбэков как 15k или около того имеет большой смысл независимо от производительности. Или, по крайней мере, специальный корпус, если это когда-нибудь случится.

-Eliot

Я думаю, что вам будет довольно трудно достичь предела ... и со временем, если вы обновитесь ... вам придется беспокоиться все меньше и меньше.

Суть ограничения заключается в том, что вы не используете всю оперативную память на своем сервере (так как вам нужно загрузить все MBдокументы в оперативную память при запросе).

Таким образом, ограничение составляет несколько% от нормальной используемой оперативной памяти в общей системе ... которая будет расти из года в год.

Замечание о хранении файлов в MongoDB

Если вам нужно хранить документы (или файлы) больше, чем 16MBвы можете использовать GridFS API, который автоматически разбивает данные на сегменты и направляет их обратно вам (таким образом, избегая проблемы с ограничениями размера / оперативной памяти.)

Вместо того, чтобы хранить файл в одном документе, GridFS делит файл на части или порции и сохраняет каждый фрагмент как отдельный документ.

GridFS использует две коллекции для хранения файлов. В одной коллекции хранятся фрагменты файлов, а в другой - метаданные файлов.

Вы можете использовать этот метод для хранения изображений, файлов, видео и т. Д. В базе данных так же, как в базе данных SQL. Я использовал это, чтобы даже хранить мульти гигабайтные видеофайлы.

Джастин Дженкинс
источник
2
Удивительно, что у вас достаточно ОЗУ для всей базы данных ... Обычно «рабочий набор» находится в ОЗУ, а не во всей базе данных (как в моем случае, у меня есть более одной базы данных по x ГБ, где, если все сложенное будет превышать мою ОЗУ, но это нормально, потому что рабочий набор намного, намного меньше.) Кроме того, если бы не было предела, вы могли бы загрузить документ объемом 800 МБ в ОЗУ с одним запросом и документ объемом 400 КБ с другим, что немного затруднило бы балансировку ОЗУ и т. д. Таким образом, «предел» составляет несколько% от обычной серверной оперативной памяти (таким образом, она увеличивается со временем.) Mongodb.org/display/DOCS/Checking+Server+Memory+Usage
Джастин Дженкинс
3
Здорово, что вы можете хранить все в оперативной памяти, но учитывайте эффективность и идиому в блоге. Вы, очевидно, хотите, чтобы сообщение было в памяти, если оно прочитано. Но действительно ли вы хотите, чтобы 10 страниц комментариев для поста блога были в памяти, когда большинство людей никогда не будут читать за первой страницей? Конечно, вы можете сделать это, и если ваша база данных достаточно мала, чтобы она могла поместиться в памяти, тогда нет проблем. Но с точки зрения чистой эффективности, вы не хотите, чтобы бесполезные биты занимали место в памяти, если вы можете этого избежать (и это касается и RDBMS).
AlexGad
50
милый Иисус, так что аргумент Монго таков: "16 МБ должно быть достаточно для всех"? Это не похоже на то, что когда-либо было неверным в прошлом.
Роберт Христос
2
Это кажется слишком плохим для меня. Mongo должен быть полезен для больших данных, не иметь таких ограничений. В моем проекте мне нужно объединить и сгруппировать твиты, связанные с одной и той же тенденцией, и это может закончиться более чем 20000 твитами за период времени в 20 часов (и вполне возможно, что тренды будут длиться дольше, чем 20 часов в моем БД). Наличие такого большого количества твитов и одновременное хранение их текста является разрушительным, а после группировки нескольких небольших трендов это заканчивается исключением большого тренда.
Саввас Парастатидис
7
@savvas, почему бы тебе поместить все твиты в один документ? Используйте один документ на твит, добавьте тему обсуждения в качестве другого поля в документе. поместите индекс в это поле темы и затем агрегируйте в этом поле, используя конвейер Монго. чтобы настроить nosql, нужно внести некоторые коррективы в то, как вы настроите свои методы и решите, что он отлично работает для многих случаев использования больших данных.
schmidlop
32

Многие в сообществе предпочли бы не ограничивать количество предупреждений о производительности, см. Этот комментарий для аргументированного аргумента: https://jira.mongodb.org/browse/SERVER-431?focusedCommentId=22283&page=com.atlassian.jira.plugin. system.issuetabpanels: комментарий-tabpanel # комментарий-22283

На мой взгляд, ведущие разработчики упрямы в этом вопросе, потому что они решили, что это важная «особенность» на раннем этапе. Они не собираются менять это в ближайшее время, потому что их чувства обижены тем, что кто-то подверг сомнению это. Еще один пример того, как личность и политика отвлекают от продукта в сообществах с открытым исходным кодом, но это не является серьезной проблемой.

marr75
источник
5
Я полностью согласен с вами, так как в настоящее время это противоречит цели встраивания документов, поскольку большинство встроенных документов теперь легко пересекают границы. Esp с множеством документов внутри них
Шарджил Ахмед
@ marr75 сейчас написано исправлено, исправлено?
Мафия
1
Я имею в виду, предел был увеличен до 16 МБ, что не решает проблему в долгосрочной перспективе; ИМО предел должен быть просто устранен.
marr75
2
6 лет нить некро. Я совершенно не убежден в вашем конкретном неудачном примере использования / примере дизайна. Кроме того, этот пример гораздо лучше иллюстрирует необходимость проверки входных данных, чем ограничение размера одного документа в базе данных. Заставить приложение разделить вложенные документы как отдельные документы в другой коллекции или запустить новый документ «продолжения» (решения, которые я использовал несколько раз для работы в рамках этого лимита), мало повлияло на производительность, но сильно повлияло на сложность кода. Весь смысл БД документов - локальность данных.
marr75
4
Спасибо за выполнение той же математики, что и документы mongoDB, чтобы защитить это решение, но ваш единственный вариант использования и мысленный эксперимент далеко не окончательны. Мне пришлось придумать сложные, избыточные конструкции, чтобы обойти тот факт, что существует произвольный предел, который попадает под действие монго (без глубоко вложенных или дублированных записей, кстати). По вашей логике, ни одна база данных не должна содержать более 16 МБ общего объема, поскольку некоторый произвольный текст может быть представлен с использованием меньшего объема памяти. Это явно глупо.
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мг.

Вложенные документы и вложенные объекты учитываются по размеру документа.

Sammaye
источник
По иронии судьбы, самая большая структура, которая может быть представлена ​​в BSON, также является самой компактной. Несмотря на то, что MongoDB использует size_t(64-битные) индексы массивов внутри, предельный размер документа в 16 МБ, в лучшем случае, сможет представлять документ, содержащий сам один массив, содержащий два миллиона 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

Возможно хранение в блоге -> комментарии отношение в не реляционную базу данных на самом деле не лучший дизайн.

Вероятно, вы все равно должны хранить комментарии в отдельной коллекции к сообщениям в блоге.

[редактировать]

Смотрите комментарии ниже для дальнейшего обсуждения.

MCHL
источник
15
Я совсем не согласен. Комментарии в документах вашего блога должны быть в порядке в MongoDB ... это очень распространенное использование (я использую его более чем в одном месте, и оно работает довольно хорошо.)
Джастин Дженкинс
2
Возможно, я был слишком строг в своем ответе. Нет ничего плохого в хранении сообщений блога и связанных комментариев в MongoDB или аналогичной базе данных. Более того, люди склонны чрезмерно использовать возможности баз данных, основанные на документах (наиболее радикальный пример - хранить все ваши данные в одном документе под названием «блог»)
Mchl
3
@Mchel: «блог» - это нехорошо, но хранить комментарии в отдельной коллекции так же плохо по тем же причинам. Сообщения с массивом комментариев, как, канонический пример документа БД.
Мэтт Бриггс
6
@SoPeople: хранение комментариев внутри поста похоже на канонический пример документно-ориентированных баз данных. (как хранение всего текста вики внутри одного документа) Если бы я писал SO, он бы полностью работал на MongoDB. Ни одна из этих записей SO не будет разумно превышать 4 МБ. Craigslist выполняет гигантскую миграцию БД своей истории в MongoDB. У них было только несколько документов, превышающих этот лимит, и ведущий разработчик предположил, что сами документы действительно были повреждены (результат некоторых ошибок). Опять же 4 мег это несколько романов текста.
Гейтс VP
3
@Gates VP, я согласен на использование отдельного полнотекстового движка. Я думал о поиске метаданных. Что, если у вас есть набор Книжных документов, и вы хотите найти все книги, изданные в 1982 году? Если каждая книга содержит + 100 КБ текста, вы не хотите передавать несколько мегабайт только для отображения первых 20 названий книг.
Микероби
0

Согласно https://www.mongodb.com/blog/post/6-rules-of-thumb-for-mongodb-schema-design-part-1

Если вы ожидаете, что запись в блоге может превышать ограничение в 16 МБ, вы должны извлечь комментарии в отдельную коллекцию, сослаться на запись блога из комментария и выполнить соединение на уровне приложения.

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

// comments
[
  {
    text: 'a comment'
    post: ObjectID('AAAA')
  },
  {
    text: 'another comment'
    post: ObjectID('AAAA')
  }
]
mzarrugh
источник