Uwaga: Ta odpowiedź jest oparta na MongoDB 3.2.4.
Warto odkryć zastosowanie explain()
w MongoDB. explain()
dane wyjściowe zapytania (np. db.collection.explain().find(...)
) umożliwia sprawdzenie, który indeks jest używany w zapytaniu, i użycie db.collection.explain('executionStats')
pokaże również, czy zapytanie się powiedzie, czy nie, z powodu znajdującego się w pamięci SORT
ograniczenia.
$w
$in
zapytanie można traktować jako serię zapytań o równość. Na przykład {a: {$in: [1,3,5]}}
można uznać za {a:1}, {a:3}, {a:5}
. MongoDB posortuje $in
tablicę przed kontynuowaniem zapytania, aby {$in: [3,5,1]}
nie różni się od {$in: [1,3,5]}
.
Załóżmy, że kolekcja ma indeks
{a:1, b:1}
-
Sortowanie według
a
db.coll.find({a: {$in: [1,3,5]}}).sort({a:1})
MongoDB będzie mógł korzystać z
{a:1,b:1}
indeks, ponieważ to zapytanie może być traktowane jako połączenie{a:1}, {a:3}, {a:5}
zapytania. Sortowanie według{a:1}
umożliwia użycie prefiksu indeksu , więc MongoDB nie musi wykonywać sortowania w pamięci.Ta sama sytuacja dotyczy również zapytania:
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({a:1})
od
sort({a:1})
używa również prefiksu indeksu (a
w tym przypadku), w pamięciSORT
etap nie jest zatem wymagany. -
Sortowanie według
b
Jest to ciekawszy przypadek w porównaniu z sortowaniem według
a
. Na przykład:db.coll.find({a: {$in: [1,3,5]}}).sort({b:1})
explain()
wyjście tego zapytania będzie miało etap o nazwieSORT_MERGE
. Pamiętaj, żefind()
część zapytania można traktować jako{a:1}, {a:3}, {a:5}
.Zapytanie
db.coll.find({a:1}).sort({b:1})
nie musi mieć w pamięciSORT
etap ze względu na charakter{a:1,b:1}
index:to znaczy, MongoDB może po prostu przejrzeć (posortowany) indeks i zwrócić dokumenty posortowane wedługb
po spełnieniu parametru równości naa
. Np. dla każdegoa
, istnieje wieleb
które są już posortowane wedługb
ze względu na indeks.Korzystanie z
$in
, ogólne zapytanie można traktować jako:db.coll.find({a:1}).sort({b:1})
db.coll.find({a:3}).sort({b:1})
db.coll.find({a:5}).sort({b:1})
- Weź powyższe wyniki poszczególnych zapytań i wykonaj scalanie przy użyciu wartości
b
. Zapytanie nie wymaga etapu sortowania w pamięci ponieważ wyniki poszczególnych zapytań są już posortowane wedługb
. MongoDB wystarczy połączyć (już posortowane) wyniki podzapytania w jeden wynik.
Podobnie zapytanie
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({b:1})
używa również
SORT_MERGE
etap i jest bardzo podobny do powyższego zapytania. Różnica polega na tym, że poszczególne zapytania do dokumentów wyjściowych są oparte na zakresieb
(zamiast cob
) dla każdegoa
(które zostaną posortowane wedługb
ze względu na indeks{a:1,b:1}
). Dlatego zapytanie nie wymaga etapu sortowania w pamięci.
$lub
Dla $or
zapytanie do użycia indeksu, każda klauzula w $or
wyrażenie musi mieć powiązany z nim indeks
. Jeśli ten wymóg jest spełniony, zapytanie może użyć SORT_MERGE
etap tak jak $in
zapytanie. Na przykład:
db.coll.explain().find({$or:[{a:1},{a:3},{a:5}]}).sort({b:1})
będzie miał prawie identyczny plan zapytań, użycie indeksu i SORT_MERGE
etap jak w $in
przykład powyżej. Zasadniczo zapytanie można traktować jako:
db.coll.find({a:1}).sort({b:1})
db.coll.find({a:3}).sort({b:1})
db.coll.find({a:5}).sort({b:1})
- Weź powyższe wyniki poszczególnych zapytań i wykonaj scalanie przy użyciu wartości
b
.
podobnie jak $in
przykład wcześniej.
Jednak to zapytanie:
db.coll.explain().find({$or:[{a:1},{b:1}]}).sort({b:1})
nie można używać żadnego indeksu (ponieważ nie mamy {b:1}
indeks). To zapytanie spowoduje przeskanowanie kolekcji i w konsekwencji będzie miał etap sortowania w pamięci ponieważ nie jest używany żaden indeks.
Jeśli jednak utworzymy indeks {b:1}
, zapytanie będzie przebiegać następująco:
db.coll.find({a:1}).sort({b:1})
db.coll.find({b:1}).sort({b:1})
- Weź powyższe wyniki poszczególnych zapytań i wykonaj scalanie przy użyciu wartości
b
(który jest już posortowany w obu zapytaniach podrzędnych, ze względu na indeksy{a:1,b:1}
i{b:1}
).
a MongoDB połączy wyniki {a:1}
i {b:1}
zapytań i wykonaj scalanie wyników. Proces scalania jest czasem liniowym, m.in. O(n)
.
Podsumowując, w $or
zapytanie, każdy termin musi mieć indeks, w tym sort()
etap. W przeciwnym razie MongoDB będzie musiał wykonać sortowanie w pamięci.