Забележка: Този отговор е базиран на 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}
-
Сортиране по
adb.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 ще трябва да извърши сортиране в паметта.