MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Как работи сортирането с `$or` и `$in` заявки в MongoDB?

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




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Четене на масив в mongodb?

  2. MongoDB $concatArrays

  3. Изпълнение на MongoDB заявки в Map/Reduce

  4. Как да видите или промените опциите за сортиране, зададени в колекция MongoDB?

  5. Стартирайте Mahout RowSimilarity препоръчител на MongoDB данни