Дизайн схемы MongoDB - много небольших документов или меньше больших документов?

88

Предпосылки
Я создаю прототип преобразования нашей базы данных СУБД в MongoDB. При денормализации кажется, что у меня есть два варианта: один ведет к множеству (миллионам) меньших документов, а другой ведет к меньшему количеству (сотням тысяч) больших документов.

Если бы я мог свести его к простому аналогу, это была бы разница между коллекцией с меньшим количеством документов Customer, подобными этой (на Java):

class Customer {
    частное строковое имя;
    частный адресный адрес;
    // каждая CreditCard имеет сотни экземпляров Payment
    частные кредитные карты Set <CreditCard>;
}

или коллекция с большим количеством Платежных документов, подобных этой:

class Payment {
    частный заказчик;
    частная CreditCard CreditCard;
    приватная дата payDate;
    private float payAmount;
}

Вопрос:
Разработана ли MongoDB для предпочтения большого количества маленьких документов или меньшего количества больших документов? Зависит ли ответ в основном от того, какие запросы я планирую запустить? (т.е. Сколько кредитных карт у клиента X? Какая средняя сумма была выплачена всеми клиентами в прошлом месяце?)

Я много оглядывался, но не наткнулся на какие-либо передовые практики схемы MongoDB, которые помогли бы мне ответить на мой вопрос.

Андре
источник

Ответы:

82

Вам определенно потребуется оптимизация для запросов, которые вы делаете.

Вот мое лучшее предположение, основанное на вашем описании.

Вероятно, вы захотите узнать все кредитные карты для каждого клиента, поэтому храните их в объекте Customer. Вы также, вероятно, захотите иметь ссылку на клиента для каждого платежа. Это позволит сохранить Платежный документ относительно небольшим.

Объект «Платеж» автоматически получит собственный идентификатор и индекс. Вы, вероятно, захотите также добавить указатель к ссылке клиента.

Это позволит вам быстро искать Платежи по Клиенту, не сохраняя каждый раз весь объект клиента.

Если вы хотите ответить на такие вопросы, как «Какая средняя сумма была уплачена всеми клиентами в прошлом месяце», вам вместо этого понадобится карта / сокращение для любого большого набора данных. Вы не получите этот ответ "в реальном времени". Вы обнаружите, что хранение «ссылки» на клиента, вероятно, достаточно для этих сокращений карты.

Итак, чтобы прямо ответить на ваш вопрос: разработан ли MongoDB для предпочтения большого количества небольших документов или меньшего количества больших документов?

MongoDB разработан для очень быстрого поиска проиндексированных записей. MongoDB очень хорошо умеет находить несколько иголок в большом стоге сена. MongoDB не очень хорошо умеет находить большинство иголок в стоге сена. Так что создавайте свои данные на основе наиболее распространенных вариантов использования и напишите задания map / reduce для более редких вариантов использования.

Гейтс ВП
источник
30

Согласно собственной документации MongoDB, похоже, что она предназначена для множества небольших документов.

Из лучших практик производительности для MongoDB :

Максимальный размер документов в MongoDB - 16 МБ. На практике размер большинства документов составляет несколько килобайт или меньше. Считайте документы больше похожими на строки в таблице, чем на сами таблицы. Вместо того, чтобы хранить списки записей в одном документе, вместо этого сделайте каждую запись документом.

Из 6 практических правил проектирования схемы MongoDB: Часть 1 :

Моделирование один-к-нескольким

Примером «один к нескольким» могут быть адреса человека. Это хороший вариант использования для встраивания - вы должны поместить адреса в массив внутри вашего объекта Person.

Один ко многим

Примером «один ко многим» могут быть детали для продукта в системе заказа запасных частей. У каждого продукта может быть до нескольких сотен запасных частей, но не более пары тысяч или около того. Это хороший вариант использования для ссылки - вы должны поместить ObjectID частей в массив в документе продукта.

Один к сквиллионам

Примером «один-к-сквиллионам» может быть система регистрации событий, которая собирает сообщения журнала для разных машин. Любой конкретный хост может сгенерировать достаточно сообщений для переполнения документа размером 16 МБ, даже если все, что вы сохранили в массиве, было ObjectID. Это классический вариант использования «родительской ссылки» - у вас будет документ для хоста, а затем вы сохраните ObjectID хоста в документах для сообщений журнала.

bmaupin
источник
11

Документы, которые со временем существенно увеличиваются, могут быть бомбой замедленного действия. Пропускная способность сети и использование ОЗУ, скорее всего, станут измеримыми узкими местами, заставляя вас начинать все сначала.

Сначала рассмотрим две коллекции: Customer и Payment. Таким образом, зерна достаточно мало: один документ на платеж.

Затем вы должны решить, как моделировать учетную информацию, например кредитные карты. Давайте рассмотрим, содержат ли документы клиента массивы информации об аккаунте или вам нужна новая коллекция Account.

Если учетные документы отделены от документов клиентов, загрузка всех учетных записей одного клиента в память требует загрузки нескольких документов. Это может привести к дополнительной памяти, вводу-выводу, пропускной способности и использованию ЦП. Означает ли это, что сбор данных по аккаунту - плохая идея?

Ваше решение влияет на платежные документы. Если информация о счете встроена в документ клиента, как бы вы на нее ссылались? У отдельных учетных документов есть собственный атрибут _id. Со встроенной информацией об учетной записи ваше приложение будет либо генерировать новые идентификаторы для учетных записей, либо использовать атрибуты учетной записи (например, номер учетной записи) для ключа.

Может ли платежный документ действительно содержать все платежи, произведенные в установленный срок (например, день?). Такая сложность коснется всего кода, который читает и записывает платежные документы. Преждевременная оптимизация может быть смертельной для проектов.

Как и в расчетных документах, на платежи легко ссылаться, если платежный документ содержит только один платеж. Новый тип документа, например кредит, может ссылаться на платеж. Но создадите ли вы кредитную коллекцию или встроите кредитную информацию в платежную информацию? Что произойдет, если вам позже понадобится ссылка на кредит?

Подводя итог, я добился успеха с множеством небольших документов и множеством коллекций. Реализую ссылки с _id и только с _id. Таким образом, я не беспокоюсь о том, что постоянно растущее количество документов разрушит мое приложение. Схема проста для понимания и индексации, поскольку каждая сущность имеет свою собственную коллекцию. Важные объекты не скрываются внутри других документов.

Я хотел бы услышать о ваших выводах. Удачи!

Террис
источник