2016-05-09 2 views
1

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

Это вопрос, который касается. Как мне создать свои коллекции здесь. Я пробовал следующие

Подход 1. Создайте коллекцию с именем subscription_book_association, где один документ соответствует подписке, и я сохраняю все идентификаторы книг для этой подписки как json внутри документа. Здесь я сталкиваюсь с проблемой, когда, если для подписки есть более 0,4 миллиона книг, я должен хранить идентификаторы всех этих книг в одном документе, и я в конечном итоге превысил лимит в 16 МБ для документа.

Подход 2. Создайте коллекцию с именем book_subscription_association, где один документ соответствует книге, и я сохраняю все идентификаторы подписки для каждой книги (в виде массива) внутри документа. В этом случае я вижу, что всякий раз, когда я выполняю операцию записи по своим данным (например, присваивать/отменять несколько новых книг для подписки), мне в основном нужно обновить массив подписки, используя оператор $ push/$ pull. Это, кажется, слишком долго (скажем, 3-4 минуты).

Например:

Подписка

{ 
     "_id" : "Standard", 
     "description" : "Standard Subscription",     
     "status" : "Active",   
} 

Книга

{ 
     "_id" : "", 
     "name" : "Java for beginners", 
     "code" : "TECH", 
     "vendor" : "XX Publications" 
     "Author" : "AAA" 
     "Year" : "2010"  
} 

book_subscription_association

{ 
     "_id" : "",   
     "code" : "TECH",   
     "displayName" : "TECH/Java for beginners", 
     "name" : "Java for beginners", 
     "permission" : [ 
       "Standard:R", 
       "Guest:R" 
       "Premium:RW"     
     ], 
     "roles" : [ 
       "Standard", 
       "Premium", 
       "Guest" 
     ] 
} 

Запрос на обновление

db.book_subscription_association.update({ }, { $pull: { roles: "Guest" } }, false,true) 
db.book_subscription_association.update({ }, { $push: { roles: "Guest" } }, false,true) 

Подход 3. Создайте коллекцию с именем book_subscription_mapping (например, таблицу сопоставления в РСУБД), где я храню ассоциацию отдельно для каждой книги по каждой применимой подписке. В этом случае количество документов, которые у меня есть в этой коллекции, очень велико. Хуже всего то, что у меня есть (2 миллиона X 200) документов в этой коллекции. Это поглощает много памяти и запросы на обновление/чтение также не очень эффективны.

+0

Вариант 2 представляется мне логичным. Чтобы решить проблему выполнения, я бы использовал ['$ explain'] (https://docs.mongodb.com/manual/reference/operator/meta/explain/), чтобы понять, где это узкое место, и попытаться найти индекс, который поможет. – OzW

+0

Более того, я думаю, что это будет полезно, если вы покажете, как выглядят ваши документы, и как выглядит ваша команда обновления. – OzW

+0

Спасибо .. Я обновил образцы данных jsons в исходном вопросе. –

ответ

0

Подход, который вы принимаете, должен основываться на типах запросов, которые вы ожидаете чаще.

Например, если вы ожидаете большего количества запросов о том, какие доступные книги в подписке, вы должны включить в свой подписной документ список, содержащий сведения, которые вы хотите показать пользователю (id, title и т. Д.).

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

Практически в вашем случае выбор между подходом 1 или подходом 2 строго зависит от того, как вы ожидаете, что ваши запросы будут иметь место.

Что касается вашей озабоченности хранением идентификаторов для подхода 1, вы можете использовать обратный подход, если коллекция книг для подписки становится очень большой (храните в отдельном поле только идентификаторы книг, которые НЕ включены в эту конкретную подписка). В зависимости от ожидаемого покрытия подписки это может быть действительно эффективным как общий шаблон.

Если этот обратный подход не работает (у вас по-прежнему слишком много книг в каждой подписке), тогда ваш лучший курс действий - следовать подходу 2 и индексировать массив, содержащий список подписки. Команды обновления, которые вы показывали в сообщении, влияют на всю коллекцию (2 мил), поэтому естественно, что они занимают немного больше времени.

Для получения дополнительной информации о том, как денормализовать таблицы, у MongoDB есть nice series of blog posts on the topic.

+0

только два варианта использования. (1) Я хочу получить книги для одного или список подписки. (2) Я хочу добавить или удалить кучу книг из одной или нескольких подписчиков. для обратного подхода, даже если я пытаюсь сохранить список книг, которые не привязаны к подписке, я по-прежнему сталкивался с сценарием 16 МБ, потому что у меня практически есть 1 миллион книг, которые назначены, и 1 миллион, которые не назначены. Когда я попытался сохранить идентификаторы книг в подписке, максимальный размер, который я мог бы поразить с помощью mongo, созданного по умолчанию, составлял примерно 0,4 миллиона. Помимо этого мой документ превысил 16 МБ –

0

Денормализация - это первое, что вам следует учитывать при моделировании ваших коллекционных документов. Вы можете сохранить как «Данные книги &« Данные подписки »в единой коллекции, поэтому всегда рекомендуется хранить все связанные данные для запроса или последовательности запросов на одном и том же диске (тот же сбор) для повышения производительности.

Используйте приведенную ниже ссылку для создания эффективной модели.

Ссылка: Updating large number of records in a collection

Смежные вопросы