Индексите в MongoDB се съхраняват в структура на B-дърво, където всеки вход в индекс сочи към конкретно място на диска. Използването на структура на B-дърво означава също, че индексът на MongoDB се съхранява в сортиран ред, винаги се преминава в ред и е евтино за MongoDB да извлича серия от документи в сортиран ред чрез индекси.
Актуализиране :Структурата на B-дърво е вярна за MMAPv1 механизма за съхранение, но се реализира малко по-различно от механизма за съхранение на WiredTiger (по подразбиране от MongoDB 3.2). Основната идея остава същата, където е евтино да преминете през индекса в сортиран ред.
A SORT
етап (т.е. сортиране в паметта) в заявка е ограничен до 32MB използване на паметта. Заявката ще бъде неуспешна, ако SORT
етап надвишава тази граница. Това ограничение може да бъде заобиколено чрез използване на сортирания характер на индексите, така че MongoDB да може да върне заявка с sort()
параметър без извършване на сортиране в паметта.
Да приемем, че заявката е във формата:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort(...)
с колекция a
с индекс от:
db.a.createIndex({b:1,c:1})
Има два възможни сценария, когато sort()
етап е посочен в заявката:
1. MongoDB не може да използва сортирания характер на индекса и трябва да извърши SORT
в паметта етапа .
Това е резултатът, ако заявката не може да използва "индексния префикс". Например:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort({c:1})
В заявката по-горе индексът {b:1,c:1}
може да се използва за:
- Свържете документи с
b
по-голямо от 100 за{b:{$gt:100}}
част от заявката. - Въпреки това, няма гаранция, че върнатите документи са сортирани по отношение на
c
.
Следователно MongoDB няма друг избор, освен да извърши сортиране в паметта. explain()
изходът на тази заявка ще има SORT
сцена. Това SORT
етап ще бъде ограничен до 32MB използване на паметта.
2. MongoDB може да използва сортирания характер на индекса .
Това е резултатът, ако заявката използва:
- Ключове за сортиране, които съответстват на реда на индекса, и
- Указва същия ред като индекса (т.е. индекса
{b:1,c:1}
може да се използва заsort({b:1,c:1})
илиsort({b:-1,c:-1})
но не иsort({b:1,c:-1})
)
Например:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort({b:1})
В заявката по-горе индексът {b:1,c:1}
може да се използва за:
- Свържете документи с
b
по-голямо от 100 за{b:{$gt:100}}
част от заявката. - В този случай MongoDB може да гарантира, че върнатите документи са сортирани по отношение на
b
.
explain()
изходът на заявката по-горе ще не имат SORT
сцена. Също така, explain()
изход на заявката със и без sort()
са идентични . По същество получаваме sort()
безплатно.
Полезен ресурс за разбиране на тази тема е Оптимизирането на съставните индекси на MongoDB. Моля, имайте предвид, че тази публикация в блога е написана още през 2012 г. Въпреки че част от терминологията може да е остаряла, техническите характеристики на публикацията все още са уместни.
Актуализация на последващи въпроси
-
MongoDB използва само един индекс за повечето заявки. Така например, за да избегнете
SORT
в паметта етап в заявкатаdb.a.find({a:1}).sort({b:1})
индексът трябва да покрива и двата
a
иb
полета по едно и също време; напр. съставен индекс като{a:1,b:1}
изисква се. Не можете да имате два отделни индекса{a:1}
и{b:1}
и очаквайте{a:1}
индекс, който ще се използва за частта за равенство, и{b:1}
индекс, който да се използва за частта за сортиране. В този случай MongoDB ще избере един от двата индекса.Следователно е правилно резултатите да се сортират, защото се търсят и връщат в реда на индекса.
-
За да избегнете сортиране в паметта с помощта на съставен индекс, първата част на индекса трябва да отговаря на частта за равенство на заявката, а втората част трябва да отговаря на частта за сортиране на заявката (както е показано в обяснението за (1) по-горе).
Ако имате запитване като това:
db.a.find({}).sort({a:1})
индексът
{a:1,b:1}
може да се използва за частта за сортиране (тъй като основно връщате цялата колекция). И ако вашата заявка изглежда така:db.a.find({a:1}).sort({b:1})
същия индекс
{a:1,b:1}
може да се използва и за двете части на заявката. Също така:db.a.find({a:1,b:1})
може също да използва същия индекс
{a:1,b:1}
Забележете модела тук:
find()
последвано отsort()
параметрите следват реда на индекса{a:1,b:1}
. Следователно съставният индекс трябва да бъде подреден по равенство -> сортиране .
Актуализация относно сортирането на различни видове
Ако полето има различни типове между документите (напр. if a
е низ в един документ, число в други, булев в друг), как протича сортирането?
Отговорът е ред за сравнение на типа MongoDB BSON. За да перифразирам страницата с ръководството, редът е:
- MinKey (вътрешен тип)
- Null
- Числа (цели, дълги, двойни, десетични)
- Символ, низ
- Обект
- Масив
- BinData
- ObjectId
- Булева
- Дата
- Часово клеймо
- Регулярен израз
- MaxKey (вътрешен тип)
Така че от примера по-горе, използвайки възходящ ред, първо ще се появят документи, съдържащи числа, след това низове, след това булеви.