MongoDB: производительность запросов на диапазонах

В этом посте пример работы с запросом и построением индекса в базе данных для MongoDB.

Есть запрос:

// Запрос:
db.drivers.find({"country": {"$in": ["A", "G"]}).sort({"carsOwned": 1})

// Индекс:
// {"country": 1, "carsOwned": 1}

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

db.collection.find({"country": "A"}).sort({"carsOwned": 1})

Мы должны создать такой индекс:

db.collection.ensureIndex({"country": 1, "carsOwned": 1})

Что если большинство запросов в условии используют выбор диапазона вместо сравнения? Как в этом:

db.collection.find({"country": {"$in": ["A", "G"]}}).sort({"carsOwned": 1})

Здесь мы использовали оператор $in, но кроме него есть ещё такие как: $gt, $lt, и др. Если вы будете использовать подобный запрос, вы увидите что он не эффективен, при этом вы помните основы — нужно запустить .explain() и посмотреть какой индекс используется и как.

В результате выполнения .explain() Вы увидите {scanAndOrder: true}, что значит MongoDB выполняет сортировочные операции, а это дорогая операция т.к. MongoDB сортирует документы в памяти. Поэтому Вы должны избегать большых наборов данных т.к. это медленно и ресурсоемко.

Не нужно забывать, почему scanAndOrder медленный, почему MongoDB сортирует результат хотя у нас уже есть индекс с сортировкой? Ответ простой: у нас нет подходящего индекса.

Почему? Причина проста, дело в структуре индекса который мы создали. Для примера выше, документы имеющие {“country”: “A”} и документы имеющие {“country”: “G”} отсортированы в индиксе по {“carsOwned”: 1}, но они сортируются независимо друг от друга. Они не отсортированы вместе! Рассмотрим диаграмму ниже:

MongoDB query

На левой схеме показан порядок обхода документов по индексу который мы создали. После того как все документы будут найдены, их нужно будет отсортировать. На правой схеме альтернативный индекс { “carsOwned”: 1, “country”: 1}. В этом случае найденые документы будут уже в отсортированном виде. Этот тонкий момент эффективности привел к следующим правилам при индексации:

Порядок полей должен быть:

  1. Сначала поля которые отбираются по точным значениям.
  2. Далее поля по которым будет идти сортировка.
  3. И в конце поля для диапазонного фильтра.
2019-12-28 07:35:05