Забележка: Този отговор е базиран на MongoDB 3.2.4.
Заслужава си да откриете използването на explain()
в MongoDB. explain()
изход на заявка (напр. db.collection.explain().find(...)
) ви позволява да проверите кой индекс се използва в заявка и да използвате db.collection.explain('executionStats')
също така ще ви покаже дали заявката е успешна или неуспешна поради SORT
в паметта ограничение.
$in
A $in
заявката може да се разглежда като поредица от заявки за равенство. Например {a: {$in: [1,3,5]}}
може да се разглежда като {a:1}, {a:3}, {a:5}
. MongoDB ще сортира $in
масив, преди да продължите със заявката, така че {$in: [3,5,1]}
не се различава от {$in: [1,3,5]}
.
Да приемем, че колекцията има индекс от
{a:1, b:1}
-
Сортиране по
a
db.coll.find({a: {$in: [1,3,5]}}).sort({a:1})
MongoDB ще може да използва
{a:1,b:1}
индекс, тъй като тази заявка може да се разглежда като обединение на{a:1}, {a:3}, {a:5}
заявки. Сортиране по{a:1}
позволява използването на индекс префикс , така че MongoDB не трябва да извършва сортиране в паметта.Същата ситуация важи и за заявката:
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({a:1})
тъй като
sort({a:1})
също използва префикса на индекса (a
в този случай),SORT
в паметта следователно етапът не е необходим. -
Сортиране по
b
Това е по-интересен случай в сравнение със сортирането по
a
. Например:db.coll.find({a: {$in: [1,3,5]}}).sort({b:1})
explain()
резултатът от тази заявка ще има етап, нареченSORT_MERGE
. Не забравяйте, чеfind()
част от заявката може да се разглежда като{a:1}, {a:3}, {a:5}
.Заявката
db.coll.find({a:1}).sort({b:1})
не е необходимо да имаSORT
в паметта поради естеството на{a:1,b:1}
индекс:т.е. MongoDB може просто да обхожда (сортирания) индекс и да връща документи, сортирани поb
след удовлетворяване на параметъра за равенство наa
. Например за всекиa
, има многоb
които вече са сортирани поb
поради индекса.Използване на
$in
, цялостната заявка може да се разглежда като:db.coll.find({a:1}).sort({b:1})
db.coll.find({a:3}).sort({b:1})
db.coll.find({a:5}).sort({b:1})
- Вземете отделните резултати от заявката по-горе и извършете сливане, като използвате стойността на
b
. Заявката не се нуждае от етап на сортиране в паметта защото отделните резултати от заявката вече са сортирани поb
. MongoDB просто трябва да обедини (вече сортираните) резултати от подзаявката в един резултат.
По същия начин, заявката
db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({b:1})
също използва
SORT_MERGE
етап и е много подобен на заявката по-горе. Разликата е, че отделните заявки извеждат документи въз основа на обхват отb
(вместо всекиb
) за всекиa
(което ще бъде сортирано поb
поради индекса{a:1,b:1}
). Следователно, заявката не се нуждае от етап на сортиране в паметта.
$или
За $or
заявка за използване на индекс, всяка клауза в $or
изразът трябва да има индекс, свързан с него
. Ако това изискване е изпълнено, възможно е заявката да използва SORT_MERGE
етап точно като $in
заявка. Например:
db.coll.explain().find({$or:[{a:1},{a:3},{a:5}]}).sort({b:1})
ще има почти идентичен план за заявка, използване на индекс и SORT_MERGE
етап като в $in
пример по-горе. По същество заявката може да се разглежда като:
db.coll.find({a:1}).sort({b:1})
db.coll.find({a:3}).sort({b:1})
db.coll.find({a:5}).sort({b:1})
- Вземете отделните резултати от заявката по-горе и извършете сливане, като използвате стойността на
b
.
точно като $in
пример преди.
Въпреки това, тази заявка:
db.coll.explain().find({$or:[{a:1},{b:1}]}).sort({b:1})
не може да използва никакъв индекс (тъй като нямаме {b:1}
индекс). Тази заявка ще доведе до сканиране на колекция и следователно ще има етап на сортиране в паметта тъй като не се използва индекс.
Ако обаче създадем индекса {b:1}
, заявката ще продължи така:
db.coll.find({a:1}).sort({b:1})
db.coll.find({b:1}).sort({b:1})
- Вземете отделните резултати от заявката по-горе и извършете сливане, като използвате стойността на
b
(което вече е сортирано и в двете подзаявки, поради индексите{a:1,b:1}
и{b:1}
).
и MongoDB ще комбинира резултатите от {a:1}
и {b:1}
заявки и извършете обединяване на резултатите. Процесът на сливане е линейно време, напр. O(n)
.
В заключение, в $or
заявка, всеки термин трябва да има индекс, включително sort()
сцена. В противен случай MongoDB ще трябва да извърши сортиране в паметта.