MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Jak sortowanie działa z zapytaniami `$or` i `$in` w MongoDB?

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ęci SORT 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 nazwie SORT_MERGE . Pamiętaj, że find() 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ęci SORT 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ług b po spełnieniu parametru równości na a . Np. dla każdego a , istnieje wiele b które są już posortowane według b 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ług b . 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 zakresie b (zamiast co b ) dla każdego a (które zostaną posortowane według b 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.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Przesyłanie i pobieranie plików za pomocą MongoDB i Spring Boot

  2. MongoDB — zapytania dotyczące projekcji

  3. Korzystanie z mongoDB w routerach Express

  4. Jak scalić wiele pól w kolekcji?

  5. django-nonrel wyklucza pole listy z admin