Почему подсказка Mongo ускоряет выполнение запроса в 10 раз?

Если я запускаю запрос монго из оболочки с помощью объяснения (), получаю имя используемого индекса, а затем снова запускаю тот же запрос, но с указанием подсказки () того же индекса, который будет использоваться — поле «миллис» из плана объяснения значительно уменьшился

Например

без подсказки:

>>db.event.find({ "type" : "X", "active" : true, "timestamp" : { "$gte" : NumberLong("1317498259000") }, "count" : { "$gte" : 0 } }).limit(3).sort({"timestamp" : -1 }).explain();

{
    "cursor" : "BtreeCursor my_super_index",
    "nscanned" : 599,
    "nscannedObjects" : 587,
    "n" : 3,
    "millis" : 24,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : true,
    "indexOnly" : false,
    "indexBounds" : { ... }
} 

указана подсказка:

>>db.event.find({ "type" : "X", "active" : true, "timestamp" : { "$gte" : NumberLong("1317498259000") }, "count" : { "$gte" : 0 } }).limit(3).sort({"timestamp" : -1 }).hint("my_super_index").explain();

{
    "cursor" : "BtreeCursor my_super_index",
    "nscanned" : 599,
    "nscannedObjects" : 587,
    "n" : 3,
    "millis" : 2,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : true,
    "indexOnly" : false,
    "indexBounds" : { ... }
} 

Разница только в поле "миллис"

Кто-нибудь знает, почему это так?

ОБНОВЛЕНИЕ: «Выбор индекса для использования» не объясняет этого, потому что монго, насколько я знаю, выбирает индекс для каждого прогона X (100?), поэтому он должен быть таким же быстрым, как с подсказкой следующий (X-1) работает


person Eugene Platonov    schedule 11.10.2011    source источник
comment
Либо индекс так сильно ускоряет работу, либо вы просто повторно выполняете кешированный запрос, который имеет гораздо меньшие накладные расходы.   -  person Marc B    schedule 11.10.2011
comment
Я не думаю, что это из-за кэширования. Если я запускаю один и тот же запрос без подсказки 2, 3 или 10 раз, он не будет намного быстрее, но всегда значительно ускоряется с подсказкой.   -  person Eugene Platonov    schedule 11.10.2011
comment
Не могли бы вы отредактировать свой вопрос, включив в него вывод find(...).explain(true) без подсказки. Это напечатает дополнительную информацию, которая может помочь отладить это.   -  person mstearn    schedule 12.10.2011
comment
Может быть, требуется 22 мс, чтобы определить, какой индекс использовать?   -  person wberry    schedule 28.03.2012
comment
Здесь подходит ответ @wberry, объяснение () с подсказкой () вернет отклоненные планы [] как пустые, поскольку выигрышный план уже был предоставлен с использованием метода подсказки (). Дельта будет более значимой для коллекции с большим количеством индексов. "rejectedPlans" : [ { "stage" : "SKIP", "skipAmount" : 493, "inputStage" : { против "rejectedPlans" : []   -  person Sindhu    schedule 10.11.2020


Ответы (4)


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

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

Ответ на аналогичный вопрос был дан здесь Понимание объяснения mongo db

person Global Warrior    schedule 21.02.2013
comment
Звучит разумно. У вас есть ссылки на документацию? - person Eugene Platonov; 23.02.2013
comment
Кроме того, операция $explain повторно оценивает набор планов запросов-кандидатов, что может привести к тому, что операция $explain будет выполняться иначе, чем обычный запрос. В результате эти операции обычно дают точное представление о том, как MongoDB будет выполнять запрос, но не отражают длину этих запросов. Когда вы запускаете объяснение() с hint(), оптимизатор запросов не переоценивает планы запросов. Извлечено из docs.mongodb.org/manual/reference/operator/explain / - person Eugene Platonov; 27.03.2013

Монго оба раза выполнял один и тот же поиск, как вы можете видеть по количеству отсканированных объектов. Также вы можете видеть, что используемый индекс был таким же (взгляните на запись «cursor»), оба уже использовали ваш индекс my_super_index.

«Подсказка» только говорит Mongo использовать этот конкретный индекс, который он уже автоматически сделал в первом запросе.

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

person StefanMK    schedule 27.03.2012
comment
Это абсолютно правильно. Ваш первый запрос выполняется дольше, потому что он выдал ошибку страницы и загрузил данные с диска. Чтобы протестировать производительность чего-то подобного, вам нужно запускать его тысячи раз при самых разных обстоятельствах, подобных тому, какой будет его производственная нагрузка, и усреднять результаты, чтобы хотя бы приблизиться к точному эталону. - person marr75; 29.03.2012
comment
Одно замечание, однако, данные, скорее всего, не в кеше, файлы базы данных отображены в памяти и только что уже загружены в системную память. Mongo упрощает работу, сопоставляя память своих файлов и позволяя операционной системе решать, когда менять страницы, почти всегда на основе частоты и давности доступа. - person marr75; 29.03.2012

Я изо всех сил пытался найти причину того же самого. Я обнаружил, что когда у нас много индексов, монго действительно занимает больше времени, чем использование подсказки. Mongo в основном занимает много времени, решая, какой индекс использовать. Подумайте о сценарии, в котором у вас есть 40 индексов, и вы выполняете запрос. Первая задача, которую необходимо выполнить Mongo, — определить, какой индекс лучше всего подходит для использования в конкретном запросе. Это означает, что mongo необходимо сканировать все ключи, а также выполнять некоторые вычисления при каждом сканировании, чтобы найти некоторый индекс производительности, если этот ключ используется. подсказка определенно ускорится, так как сканирование ключа индекса будет сохранено.

person Parag Arora    schedule 21.08.2012
comment
просто понятный ответ - person Irshad Khan; 25.01.2018

Я расскажу вам, как узнать, как это быстрее 1) без индекса Он будет тянуть каждый документ в память, чтобы получить результат 2) с индексом Если у вас много индекса для этой коллекции, он возьмет индекс из кэш-памяти 3) с .hint(_index) потребуется тот конкретный индекс, который вы упомянули

с hint() без hint() оба раза, когда вы выполняете .explain("executionStats") с hint(), тогда вы можете проверить значение totalKeysExamined, что значение будет соответствовать totalDocsExamined без подсказки() вы можете видеть, что значение totalKeysExamined больше, чем totalDocsExamined

totalDocsExamined этот результат в большинстве случаев будет точно соответствовать количеству результатов.

person Vinayak Bansal    schedule 22.04.2019