MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Wie funktioniert das Sortieren mit `$or`- und `$in`-Abfragen in MongoDB?

Hinweis: Diese Antwort basiert auf MongoDB 3.2.4.

Es lohnt sich, die Verwendung von explain() zu entdecken in MongoDB. Der explain() Ausgabe einer Abfrage (z. B. db.collection.explain().find(...)). ) können Sie überprüfen, welcher Index in einer Abfrage verwendet wird, und mit db.collection.explain('executionStats') zeigt Ihnen auch, ob die Abfrage aufgrund von SORT im Speicher erfolgreich ist oder fehlschlägt Einschränkung.

$in

Ein $in Die Abfrage kann als eine Reihe von Gleichheitsabfragen betrachtet werden. Beispiel:{a: {$in: [1,3,5]}} könnte man sich vorstellen als {a:1}, {a:3}, {a:5} . MongoDB sortiert den $in Array, bevor Sie mit der Abfrage fortfahren, sodass {$in: [3,5,1]} unterscheidet sich nicht von {$in: [1,3,5]} .

Nehmen wir an, die Sammlung hat einen Index von

{a:1, b:1}
  • Sortierung nach a

      db.coll.find({a: {$in: [1,3,5]}}).sort({a:1})
    

    MongoDB kann den {a:1,b:1} verwenden index, da diese Abfrage als Vereinigung von {a:1}, {a:3}, {a:5} betrachtet werden kann Abfragen. Sortieren nach {a:1} erlaubt die Verwendung von Indexpräfix , sodass MongoDB keine In-Memory-Sortierung durchführen muss.

    Die gleiche Situation gilt auch für die Abfrage:

      db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({a:1})
    

    seit sort({a:1}) verwendet auch das Indexpräfix (a in diesem Fall), ein speicherresidentes SORT Stufe ist daher nicht erforderlich.

  • Sortierung nach b

    Dies ist ein interessanterer Fall im Vergleich zum Sortieren nach a . Zum Beispiel:

      db.coll.find({a: {$in: [1,3,5]}}).sort({b:1})
    

    Das explain() Die Ausgabe dieser Abfrage hat eine Phase namens SORT_MERGE . Denken Sie daran, dass find() Teil der Abfrage kann man sich als {a:1}, {a:3}, {a:5} vorstellen .

    Die Abfrage db.coll.find({a:1}).sort({b:1}) muss kein SORT im Speicher haben Phase aufgrund der Natur des {a:1,b:1} index:Das heißt, MongoDB kann einfach den (sortierten) Index durchlaufen und Dokumente sortiert nach b zurückgeben nachdem der Gleichheitsparameter auf a erfüllt wurde . Z. B. für jeden a , gibt es viele b die bereits nach b sortiert sind aufgrund des Indexes.

    Verwenden von $in , kann man sich die Gesamtabfrage wie folgt vorstellen:

    • db.coll.find({a:1}).sort({b:1})
    • db.coll.find({a:3}).sort({b:1})
    • db.coll.find({a:5}).sort({b:1})
    • Nehmen Sie die einzelnen Abfrageergebnisse oben und führen Sie eine Zusammenführung mit dem Wert von b durch . Die Abfrage benötigt keine In-Memory-Sortierungsphase da die einzelnen Abfrageergebnisse bereits nach b sortiert sind . MongoDB muss nur die (bereits sortierten) Unterabfrageergebnisse zu einem einzigen Ergebnis zusammenführen.

    Ebenso die Abfrage

      db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({b:1})
    

    verwendet auch ein SORT_MERGE Stufe und ist der obigen Abfrage sehr ähnlich. Der Unterschied besteht darin, dass die einzelnen Abfragen Dokumente basierend auf einer Reihe von ausgeben b (statt alle b ) für jeden a (die nach b sortiert werden aufgrund des Index {a:1,b:1} ). Daher benötigt die Abfrage keine In-Memory-Sortierungsphase.

$oder

Für ein $or Abfrage, um einen Index zu verwenden, jede Klausel im $or Ausdruck muss ein Index zugeordnet sein . Wenn diese Anforderung erfüllt ist, kann die Abfrage einen SORT_MERGE verwenden Bühne genau wie ein $in Anfrage. Zum Beispiel:

db.coll.explain().find({$or:[{a:1},{a:3},{a:5}]}).sort({b:1})

wird einen fast identischen Abfrageplan, Indexgebrauch und SORT_MERGE haben Stufe wie in $in Beispiel oben. Im Wesentlichen kann man sich die Abfrage wie folgt vorstellen:

  • db.coll.find({a:1}).sort({b:1})
  • db.coll.find({a:3}).sort({b:1})
  • db.coll.find({a:5}).sort({b:1})
  • Nehmen Sie die einzelnen Abfrageergebnisse oben und führen Sie eine Zusammenführung mit dem Wert von b durch .

genau wie $in Beispiel vor.

Diese Abfrage jedoch:

db.coll.explain().find({$or:[{a:1},{b:1}]}).sort({b:1})

kann keinen Index verwenden (da wir den {b:1} nicht haben Index). Diese Abfrage führt zu einem Sammlungsscan und hat folglich eine In-Memory-Sortierungsphase da kein Index verwendet wird.

Wenn wir jedoch den Index {b:1} erstellen , wird die Abfrage wie folgt fortgesetzt:

  • db.coll.find({a:1}).sort({b:1})
  • db.coll.find({b:1}).sort({b:1})
  • Nehmen Sie die einzelnen Abfrageergebnisse oben und führen Sie eine Zusammenführung mit dem Wert von b durch (die bei beiden Unterabfragen bereits sortiert ist, aufgrund der Indizes {a:1,b:1} und {b:1} ).

und MongoDB kombiniert die Ergebnisse von {a:1} und {b:1} Abfragen und führen Sie eine Zusammenführung der Ergebnisse durch. Der Zusammenführungsprozess ist eine lineare Zeit, z. O(n) .

Abschließend in einem $or Abfrage muss jeder Begriff einen Index haben, einschließlich sort() Bühne. Andernfalls muss MongoDB eine In-Memory-Sortierung durchführen.