Составной индекс Mongodb не используется - PullRequest
0 голосов
/ 13 февраля 2020

У меня есть индекс mongodb с почти 100 000 документов. В каждом документе есть следующие 3 поля.

arrayX: [ObjectId] someID: Отметка времени ObjectId: Date

Я создал составной индекс для 3 полей в указанном порядке.

Когда я пытаюсь запустить агрегированный запрос (записанный ниже в псевдокоде), как

match(
  and(
    arrayX: (elematch: A),
    someId: Y
  )
)
sort (timestamp: 1)

, он не заканчивается использованием составного индекса.

Как я знаю это когда я использую .explain(), этап winPlan равен FETCH, inputStage равен IXSCAN, а indexname равен timestamp_1, что означает, что он использует только другой индекс одного ключа, который я создал для поля метки времени .

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

Ответы [ 2 ]

0 голосов
/ 13 февраля 2020

Я использую подобные документы (на основе вопроса) для обсуждения:

{
  _id: 1,
  fld: "One",
  arrayX: [ ObjectId("5e44f9ed221e963909537848"), ObjectId("5e44f9ed221e963909537849") ],
  someID: ObjectId("5e44f9e7221e963909537845"),
  timestamp: ISODate("2020-02-12T01:00:00.0Z")
}


Индексы:

Я создал два индекса , как упомянуто в сообщении с вопросом:

{ timestamp: 1 } и { arrayX:1, someID:1, timestamp:1 }


Запрос:

db.test.find( 
  { 
      someID: ObjectId("5e44f9e7221e963909537845"), 
      arrayX: ObjectId("5e44f9ed221e963909537848")
  } 
).sort( { timestamp: 1 } )

В Выше запрос я не с использованием $elemMatch. Фильтр запроса, использующий $elemMatch с условием равенства одного поля , может быть записан без $elemMatch. From $ elemMatch Условие одиночного запроса :

Если в выражении $ elemMatch указан один предикат запроса, $ elemMatch не требуется.


План запроса:

Я запустил запрос с explain и обнаружил, что запрос использует индекс arrayX_1_someID_1_timestamp_1. Индекс используется для фильтра , а также для операций sort запроса.

Пример плана:

"winningPlan" : {
        "stage" : "FETCH",
        "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                        "arrayX" : 1,
                        "someID" : 1,
                        "timestamp" : 1
                },
                "indexName" : "arrayX_1_someID_1_timestamp_1",
...

IXSCAN указывает, что запрос использует индекс. Этап FETCH указывает, что документ извлекается для получения других сведений с использованием идентификатора индекса. Это означает, что как фильтр запроса, так и сортировка используют индекс. Чтобы узнать, что сортировка использует индекс, план не будет иметь этап SORT - как в этом случае.


Ссылка:

С Сортировать и не префиксное подмножество индекса :

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

0 голосов
/ 13 февраля 2020

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

Если вы запустите объяснение с опцией allPlansExecution, ответ также покажет вам время выполнения для каждого плана, среди прочего.

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

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

Для небольших наборов данных или когда запрос будет соответствовать значительной части коллекции, план без сортировочной блокировки будет быстрее возвращать результаты.

Вы можете протестировать создание другого индекса на { someID:1, timestamp:1 }, так как это может уменьшить количество сканируемых документов, но при этом избегать блокировки сортировки.

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

Поля в разделе executeStats выходных данных объяснения объясняются в Результаты объяснения . Сравнение предполагаемого времени выполнения для каждого этапа может помочь вам определить, где вы можете настроить запросы.

...