Вы можете представить однополевый индекс MongoDB как массив с указателями на местоположение документа. Например, если у вас есть коллекция с (обратите внимание, что последовательность намеренно вышла из строя):
[collection]
1: {a:3, b:2}
2: {a:1, b:2}
3: {a:2, b:1}
4: {a:1, b:1}
5: {a:2, b:2}
Индекс одного поля
Теперь, если вы делаете:
db.collection.createIndex({a:1})
Индекс выглядит примерно так:
[index a:1]
1: {a:1} --> 2, 4
2: {a:2} --> 3, 5
3: {a:3} --> 1
Обратите внимание на три важные вещи:
- Сортируется по
a
по возрастанию
- Каждая запись указывает на место, где находятся соответствующие документы
- Индекс записывает только значения поля
a
. Поле b
вообще не существует в индексе
Так что, если вы делаете запрос, как:
db.collection.find().sort({a:1})
Все, что нужно сделать, - это пройти индекс сверху вниз, извлечь и вывести документ, на который указывают записи. Обратите внимание, что вы также можете пройти индекс снизу, например ::1010 *
db.collection.find().sort({a:-1})
и единственная разница в том, что вы идете по указателю в обратном порядке.
Поскольку b
вообще нет в индексе, вы не можете использовать индекс, когда запрашиваете что-либо о b
.
Составной индекс
в составном индексе, например ::1010 *
db.collection.createIndex({a:1, b:1})
Это означает, что вы хотите сначала отсортировать по a
, а затем по b
. Индекс будет выглядеть так:
[index a:1, b:1]
1: {a:1, b:1} --> 4
2: {a:1, b:2} --> 2
3: {a:2, b:1} --> 3
4: {a:2, b:2} --> 5
5: {a:3, b:2} --> 1
Обратите внимание:
- Индекс отсортирован по
a
- В каждом
a
у вас есть отсортированный b
- У вас есть 5 записей индекса против только трех в предыдущем примере с одним полем
Используя этот индекс, вы можете сделать запрос вроде:
db.collection.find({a:2}).sort({b:1})
Он может легко найти, где a:2
, а затем пройти указатель вперед. Учитывая этот индекс, вы не можете сделать :
db.collection.find().sort({b:1})
db.collection.find({b:1})
В обоих запросах вы не можете легко найти b
, поскольку он распространяется по всему индексу (то есть не в смежных записях). Однако вы можете сделать:
db.collection.find({a:2}).sort({b:-1})
, поскольку вы можете найти, где находится a:2
, и пройтись по b
записям назад.
Редактировать : уточнение вопроса @ marcospgp в комментарии:
Возможность использования индекса {a:1, b:1}
для удовлетворения find({a:2}).sort({b:-1})
действительно имеет смысл, если вы видите это с точки зрения отсортированной таблицы. Например, индекс {a:1, b:1}
можно рассматривать как:
a | b
--|--
1 | 1
1 | 2
2 | 1
2 | 2
2 | 3
3 | 1
3 | 2
найти ({а: 2}). Рода ({Ь: 1})
Индекс {a:1, b:1}
означает sort by a, then within each a, sort the b values
. Если вы затем выполните find({a:2}).sort({b:1})
, индекс знает, где находятся все a=2
. В пределах этого блока a=2
, b
будет отсортирован в порядке возрастания (согласно спецификации индекса), так что запрос find({a:2}).sort({b:1})
может быть удовлетворен:
a | b
--|--
1 | 1
1 | 2
2 | 1 <-- walk this block forward to satisfy
2 | 2 <-- find({a:2}).sort({b:1})
2 | 3 <--
3 | 1
3 | 2
найти ({а: 2}). Рода ({Ь: -1})
Поскольку указатель можно перемещать вперед или назад, была выполнена аналогичная процедура с небольшим поворотом в конце:
a | b
--|--
1 | 1
1 | 2
2 | 1 <-- walk this block backward to satisfy
2 | 2 <-- find({a:2}).sort({b:-1})
2 | 3 <--
3 | 1
3 | 2
Тот факт, что индекс может идти вперед или назад, является ключевым моментом, который позволяет запросу find({a:2}).sort({b:-1})
использовать индекс {a:1, b:1}
.
Объяснение планировщика запросов
Вы можете увидеть, что планирует планировщик запросов, используя db.collection.explain().find(....)
. В основном, если вы видите stage
из COLLSCAN
, индекс не использовался или не может быть использован для запроса. См. объяснение результатов для получения подробной информации о выводе команды.