Как проекция mongoDB влияет на производительность?


10

Из MongoDBдокументации упоминается, что:

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

Как поля фильтрации влияют на производительность? Связана ли производительность с размером данных, передаваемых по сети? или размер данных, которые будут храниться в памяти? Как именно эта производительность улучшается? Что это за производительность, упомянутая в документации?

У меня медленные запросы MongoDB. Влияет ли возвращаемое подмножество на мой медленный запрос (у меня есть составной индекс на поле)?


Без кода невозможно предложить вас. что на самом деле повлияет на производительность в запросе проекции "MongoDB". Всегда лучше хотя бы упомянуть код.
Г-н Хайдар Али Хан

@MdHaidarAliKhan это не о коде и моей полезной нагрузке. Я просто хочу знать, почему mongoDB говорит, что фильтрация влияет на производительность? С какой точки зрения эта производительность была измерена? Например, помогает ли это использование памяти Mongo из-за меньшего количества данных или меньшего количества дисковых операций ввода-вывода (например) и так далее.
ALH

Я просто хочу знать, почему mongoDB говорит, что фильтрация влияет на производительность? Хорошо, используйте Прогнозы для возврата только необходимых данных, я имею в виду, что вы можете добиться лучшей производительности, возвращая только те поля, которые вам нужны. Например, db.posts.find ({}, {}). Sort ({}).
Г-н Хайдар Али Хан

Например, это помогает при использовании памяти Mongo из-за меньшего количества данных или меньшего количества дисковых операций ввода-вывода (например) и так далее, хорошо ... не могли бы вы обновить, какая версия MongoDB и операционная система в вашей среде?
Г-н Хайдар Али Хан

@MdHaidarAliKhan OS is Debian 8,MongoDB 3.6.2
ALH

Ответы:


15

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

Однако использование проекции для ограничения полей для возврата из результатов запроса может повысить производительность за счет:

  • удаление ненужных полей из результатов запроса (экономия на пропускной способности сети)
  • ограничение полей результатов для выполнения покрытого запроса (возврат индексированных результатов запроса без извлечения полных документов)

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

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

Примеры

Для демонстрации с помощью mongoоболочки представьте, что у вас есть документ, который выглядит следующим образом:

db.data.insert({
    a: 'webscale',
    b: new Array(10*1024*1024).join('z')
})

Поле bможет представлять выбор значений (или в этом случае очень длинную строку).

Затем создайте индекс, по {a:1}которому часто используется поле, запрашиваемое вашим вариантом использования:

db.data.createIndex({a:1})

Простой findOne()без критериев проекции возвращает результат запроса, который составляет около 10 МБ:

> bsonsize(db.data.findOne({}))
10485805

Добавление проекции {a:1}ограничит вывод в поле aи документ _id(который включен по умолчанию). Сервер MongoDB по-прежнему манипулирует документом 10 МБ для выбора двух полей, но результат запроса теперь составляет всего 33 байта:

> bsonsize(db.data.findOne({}, {a:1}))
33

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

totalDocsExaminedИ totalKeysExaminedметрики в explain()результатах будет показано , сколько документов и ключи индекса были рассмотрены:

 > db.data.find(
     {a:'webscale'}, 
     {a:1}
 ).explain('executionStats').executionStats.totalDocsExamined
 > 1

Этот запрос можно улучшить с помощью проекции, чтобы исключить _idполе и выполнить покрытый запрос, используя только {a:1}индекс. Покрываемому запросу больше не нужно извлекать документ размером ~ 10 МБ в память, поэтому он будет эффективен как по сети, так и по использованию памяти:

 > db.data.find(
     {a:'webscale'},
     {a:1, _id:0}
 ).explain('executionStats').executionStats.totalDocsExamined
 0

 > bsonsize(db.data.findOne( {a:'webscale'},{a:1, _id:0}))
 21

У меня медленные запросы MongoDB. Влияет ли возвращаемое подмножество на мой медленный запрос (у меня есть составной индекс на поле)?

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

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


1
Я очень благодарен за подробное объяснение проблемы. Кажется, что невозможно покрыть запросы, поскольку мой ответ содержит гораздо больше данных, чем внутри индекса. Мой главный вопрос здесь, я был бы рад, если бы вы могли посмотреть: dba.stackexchange.com/questions/195065/…
ALH

1

С помощью проекции вы можете получить ситуацию, когда набор результатов будет получен непосредственно из индекса.

Если у вас есть составной индекс, {x:1, y:1, z:1}где ни один из x, y, z не равен _id, вам необходимо спроецировать, {_id:0, x:1, y:1, z:1}потому что _idон всегда возвращается как часть набора результатов (когда он не спроецирован), и движок должен читать файлы данных, чтобы получить его. Это потому, что индекс не имеет значения _id, только указатель на тот документ, где хранится значение.


Так что, если я удаляю _idиз возвращенного ответа, это помещается в RAM? Это помогает?
ALH

1
MongoD (пытается) сохранить хотя бы индексы в памяти (и столько данных, сколько подходит). Если ваш запрос может быть заполнен непосредственно из индекса, и вы проектируете, _id:0то результат возвращается полностью из ОЗУ, без чтения данных с диска.
Джусси
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.