долен ред / tl;dr: Индекс b
може да бъде „пропуснат“, ако a
и c
са запитани за равенство или неравенство, но не, например, за сортиране на c
.
Това е много добър въпрос. За съжаление не можах да намеря нищо, което да отговаря авторитетно на това по-подробно. Вярвам, че ефективността на подобни заявки се е подобрила през последните години, така че не бих се доверил на стар материал по темата.
Цялото нещо е доста сложно, защото зависи от селективността на вашите индекси и от това дали заявите за равенство, неравенство и/или сортиране, така че explain()
е единственият ти приятел, но ето някои неща, които открих:
Предупреждение :Това, което идва сега, е смесица от експериментални резултати, разсъждения и догадки. Може да разтягам аналогията на Кайл твърде далеч и може и да греша напълно (и лош късмет, защото резултатите от теста ми слабо съвпадат с разсъжденията ми).
Ясно е, че може да се използва индексът на А, който в зависимост от селективността на А със сигурност е много полезен. „Пропускането“ B може да бъде сложно или не. Нека запазим това подобно на примера с готварска книга на Кайл:
French
Beef
...
Chicken
Coq au Vin
Roasted Chicken
Lamb
...
...
Ако сега ме помолите да намеря френско ястие, наречено "Chateaubriand", мога да използвам индекс A
и тъй като не знам съставката, ще трябва да сканирам всички ястия в A
. От друга страна знам, че списъкът с ястия във всяка категория е сортиран чрез индекса C
, така че ще трябва само да търся низовете, започващи с, да речем, "Ча" във всеки списък с съставки. Ако има 50 съставки, ще ми трябват 50 прегледа вместо само една, но това е много по-добре, отколкото да се налага да сканирам всяко френско ястие!
В моите експерименти броят беше много по-малък от броя на отделните стойности в
b
:никога не изглеждаше да надвишава 2. Тествах обаче това само с една колекция и вероятно е свързано със селективността наb
-индекс.
Ако ме помолите да ви дам списък по азбучен ред на всички френски ястия , обаче щях да имам проблема . Сега индексът на C
е безполезен, ще трябва да слея и сортирам всички тези индексни списъци. Ще трябва да сканирам всеки елемент, за да го направя.
Това се отразява в моите тестове. Ето някои опростени резултати. Оригиналната колекция има дати, ints и низове, но исках да запазя нещата прости, така че вече е всичко ints.
По същество има само два класа заявки:тези, при които nscanned
<=2 * limit
, и тези, които трябва да сканират цялата колекция (120k документи). Индексът е {a, b, c}
:
// fast (range query on c while skipping b)
> db.Test.find({"a" : 43, "c" : { $lte : 45454 }});
// slow (sorting)
> db.Test.find({"a" : 43, "c" : { $lte : 45454 }}).sort({ "c" : -1});
> db.Test.find({"a" : 43, "c" : { $lte : 45454 }}).sort({ "b" : -1});
// fast (can sort on c if b included in the query)
> db.Test.find({"a" : 43, "b" : 7887, "c" : { $lte : 45454 }}).sort({ "c" : -1});
// fast (older tutorials claim this is slow)
> db.Test.find({"a" : {$gte : 43}, "c" : { $lte : 45454 }});
Вашият пробег ще варира.