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}
, но они сортируются независимо друг от друга. Они не отсортированы вместе! Рассмотрим диаграмму ниже:
На левой схеме показан порядок обхода документов по индексу который мы создали. После того как все документы будут найдены, их нужно будет отсортировать.
На правой схеме альтернативный индекс { “carsOwned”: 1, “country”: 1}
. В этом случае найденые документы будут уже в отсортированном виде.
Этот тонкий момент эффективности привел к следующим правилам при индексации:
Порядок полей должен быть:
- Сначала поля которые отбираются по точным значениям.
- Далее поля по которым будет идти сортировка.
- И в конце поля для диапазонного фильтра.