MongoDB: размер документа влияет на производительность запроса?

Предположите мобильную игру, которая поддерживается базой данных MongoDB, содержащей коллекцию User с несколькими миллионами документов.

Теперь предположим несколько десятков свойств, которые должны быть связаны с пользователем - например. массив _id значений Friend документов, их имя пользователя, фотография, массив _id значений Game документов, дата последнего_лога, количество внутриигровой валюты и т.д. и т.д. и т.д.

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

Мы, скорее всего, никогда не затмем 16mb за документ, но мы можем с уверенностью сказать, что наши документы будут на 10-20x больше, если мы будем хранить эти растущие списки напрямую.

Вопрос: это даже проблема в MongoDB? Размер документа даже имеет значение, если ваши запросы правильно управляются с помощью прогнозов и индексов и т.д.? Должны ли мы активно сокращать размер документа, например. с ссылками на внешние списки или на встраивание списков значений _id напрямую?

Другими словами: если я хочу значение пользователя last_login, будет ли запрос, который проектирует/выбирает только поле last_login, будет отличаться, если мои документы User равны 100 кб и 5 МБ?

Или: если я хочу найти всех пользователей с определенным значением last_login, размер документа повлияет на этот запрос?

Ответы

Ответ 1

Прежде всего, вы должны потратить немного времени на то, как MongoDB хранит документы со ссылкой на коэффициенты заполнения и распределение powerof2sizes:

http://docs.mongodb.org/manual/core/storage/ http://docs.mongodb.org/manual/reference/command/collStats/#collStats.paddingFactor

Проще говоря, MongoDB пытается выделить некоторое дополнительное пространство при сохранении исходного документа, чтобы обеспечить его рост. Распределение Powerof2sizes стало стандартным подходом в версии 2.6, где он увеличит размер документа с полномочиями 2.

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

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

1) Выделите достаточное пространство при первоначальной вставке, чтобы покрыть большинство (допустим, 90%) обычного срока службы документов. Хотя это будет неэффективно в использовании пространства в начале, эффективность будет возрастать со временем по мере роста документов без снижения производительности. Фактически, вы будете платить за это время за хранение, которое в конечном итоге вы будете использовать позже, чтобы получить хорошую производительность с течением времени.

2) Создайте документы "переполнения" - скажем, типичное правило 80-20, и 80% ваших документов будут соответствовать определенному размеру. Выделите эту сумму и добавьте коллекцию переполнения, которую может указать ваш документ, если у них более 100 друзей или 100 игровых документов, например. Поле переполнения указывает на документ в этой новой коллекции, и ваше приложение просматривает только новую коллекцию, если существует поле переполнения. Позволяет выполнять обычную обработку документов для 80% пользователей и позволяет избежать большого количества хранения на 80% пользовательских документов, которые ему не понадобятся, за счет дополнительной сложности приложений.

В любом случае я бы рассмотрел использование закрытых запросов, построив соответствующие индексы:

Закрытый запрос - это запрос, в котором:

all the fields in the query are part of an index, and
all the fields returned in the results are in the same index.

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

Запрос только по индексу может быть намного быстрее, чем запрос документов вне индекса. Индексные ключи обычно меньше, чем документы, которые они каталогизируют, и индексы обычно доступны в ОЗУ или расположенных последовательно на диске.

Подробнее об этом здесь: http://docs.mongodb.org/manual/tutorial/create-indexes-to-support-queries/

Ответ 2

Один из способов перефразировать вопрос состоит в том, чтобы сказать, что запрос на 1 миллион документов занимает больше времени, если документы имеют 16 МБ против 16 КБ каждый.

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

Я делал запросы по документам 500 тыс. против 25 тыс. документов, а запрос 25 тыс. был заметно быстрее - от нескольких миллисекунд до 1-3 секунд быстрее. При производстве разница во времени примерно в 2 раза больше.

Один из аспектов, в котором размер документа входит в игру, - это сортировка запросов, и в этом случае размер документа влияет на то, будет ли сам запрос работать или нет. Я неоднократно достигал этого предела, пытаясь отсортировать всего лишь 2 тыс. Документов.

Дополнительные ссылки с некоторыми решениями здесь: https://docs.mongodb.org/manual/reference/limits/#operations https://docs.mongodb.org/manual/reference/operator/aggregation/sort/#sort-memory-limit

В конце дня его конечный пользователь страдает.

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

Надеюсь, это поможет!