dolny wiersz / tl;dr: Indeksuj b
można 'pominąć', jeśli a
i c
są odpytywane o równość lub nierówność, ale nie o sortowanie na c
.
To jest bardzo dobre pytanie. Niestety nie mogłem znaleźć niczego, co by autorytatywnie odpowiadało na to bardziej szczegółowo. Uważam, że wydajność takich zapytań poprawiła się w ciągu ostatnich lat, więc nie ufałbym starym materiałom na ten temat.
Cała sprawa jest dość skomplikowana, ponieważ zależy to od selektywności twoich indeksów i tego, czy pytasz o równość, nierówność i/lub sortowanie, więc explain()
jest twoim jedynym przyjacielem, ale oto kilka rzeczy, które znalazłem:
Zastrzeżenie :To, co teraz nadchodzi, to mieszanka wyników eksperymentalnych, rozumowania i domysłów. Być może za bardzo naciągam analogię Kyle'a, a może nawet się całkowicie mylić (i pechowe, ponieważ moje wyniki testów luźno pasują do mojego rozumowania).
Oczywiste jest, że można zastosować indeks A, co w zależności od selektywności A jest z pewnością bardzo pomocne. „Pomijanie” B może być trudne lub nie. Zróbmy to podobnie do przykładu z książki kucharskiej Kyle'a:
French
Beef
...
Chicken
Coq au Vin
Roasted Chicken
Lamb
...
...
Jeśli teraz poprosisz mnie o znalezienie jakiegoś francuskiego dania o nazwie „Chateaubriand”, mogę użyć indeksu A
a ponieważ nie znam składnika, będę musiał zeskanować wszystkie potrawy w A
. Z drugiej strony wiem, że lista dań w każdej kategorii jest posortowana według indeksu C
, więc będę musiał szukać tylko ciągów zaczynających się od, powiedzmy, „Cha” na każdej liście składników. Jeśli jest 50 składników, potrzebuję 50 wyszukiwań zamiast tylko jednego, ale to o wiele lepsze niż konieczność skanowania każdego francuskiego dania!
W moich eksperymentach liczba ta była znacznie mniejsza niż liczba odrębnych wartości w b
:wydawało się, że nigdy nie przekracza 2. Jednak przetestowałem to tylko z jedną kolekcją i prawdopodobnie ma to związek z selektywnością b
-indeks.
Gdybyś poprosił mnie o posortowaną alfabetycznie listę wszystkich francuskich potraw , jednak będę miał kłopoty . Teraz indeks na C
jest bezwartościowe, musiałbym scalić i posortować wszystkie te listy indeksów. Aby to zrobić, będę musiał zeskanować każdy element.
Odzwierciedla to w moich testach. Oto kilka uproszczonych wyników. Oryginalna kolekcja zawiera daty i godziny, int i ciągi, ale chciałem, aby wszystko było proste, więc teraz zawiera wszystkie int.
Zasadniczo istnieją tylko dwie klasy zapytań:te, w których nscanned
<=2 * limit
oraz tych, które muszą zeskanować całą kolekcję (120 tys. dokumentów). Indeks to {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 }});
Twój przebieg będzie się różnić.