sql >> Database >  >> NoSQL >> MongoDB

Hoe werkt sorteren met `$or` en `$in` queries in MongoDB?

Opmerking: Dit antwoord is gebaseerd op MongoDB 3.2.4.

Het is de moeite waard om het gebruik van explain() te ontdekken in MongoDB. De explain() uitvoer van een zoekopdracht (bijv. db.collection.explain().find(...) ) stelt u in staat om te controleren welke index wordt gebruikt in een zoekopdracht en met behulp van db.collection.explain('executionStats') zal u ook laten zien of de zoekopdracht slaagt of mislukt vanwege SORT in het geheugen beperking.

$in

Een $in query kan worden gezien als een reeks gelijkheidsquery's. Bijvoorbeeld {a: {$in: [1,3,5]}} kan worden gezien als {a:1}, {a:3}, {a:5} . MongoDB sorteert de $in array voordat u doorgaat met de query, zodat {$in: [3,5,1]} is niet anders dan {$in: [1,3,5]} .

Laten we aannemen dat de collectie een index heeft van

{a:1, b:1}
  • Sorteren op a

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

    MongoDB kan de {a:1,b:1} . gebruiken index, aangezien deze zoekopdracht kan worden gezien als een samenvoeging van {a:1}, {a:3}, {a:5} vragen. Sorteren op {a:1} staat het gebruik toe van indexvoorvoegsel , zodat MongoDB geen sortering in het geheugen hoeft uit te voeren.

    Dezelfde situatie is ook van toepassing op de vraag:

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

    sinds sort({a:1}) gebruikt ook het indexvoorvoegsel (a in dit geval), een in-memory SORT podium is daarom niet vereist.

  • Sorteren op b

    Dit is een interessanter geval vergeleken met sorteren op a . Bijvoorbeeld:

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

    De explain() uitvoer van deze query heeft een fase genaamd SORT_MERGE . Onthoud dat de find() gedeelte van de zoekopdracht kan worden gezien als {a:1}, {a:3}, {a:5} .

    De zoekopdracht db.coll.find({a:1}).sort({b:1}) hoeft geen SORT in het geheugen te hebben stadium vanwege de aard van de {a:1,b:1} index:dat wil zeggen, MongoDB kan eenvoudig door de (gesorteerde) index lopen en documenten gesorteerd op b retourneren na het voldoen aan de gelijkheidsparameter op a . Bijvoorbeeld voor elke a , er zijn veel b die al zijn gesorteerd op b vanwege de index.

    $in gebruiken , kan de algemene vraag worden gezien als:

    • db.coll.find({a:1}).sort({b:1})
    • db.coll.find({a:3}).sort({b:1})
    • db.coll.find({a:5}).sort({b:1})
    • Neem de individuele zoekresultaten hierboven en voer een samenvoeging uit met de waarde b . De zoekopdracht heeft geen sorteerfase in het geheugen nodig omdat de individuele zoekopdrachtresultaten al zijn gesorteerd op b . MongoDB hoeft alleen de (reeds gesorteerde) subqueryresultaten samen te voegen tot een enkel resultaat.

    Evenzo is de vraag

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

    gebruikt ook een SORT_MERGE en lijkt erg op de bovenstaande query. Het verschil is dat de afzonderlijke query's documenten uitvoeren op basis van een bereik van b (in plaats van elke b ) voor elke a (die wordt gesorteerd op b vanwege de index {a:1,b:1} ). Daarom heeft de query geen sorteerfase in het geheugen nodig.

$of

Voor een $or query om een ​​index te gebruiken, elke clausule in de $or expressie moet een bijbehorende index hebben . Als aan deze vereiste is voldaan, kan de query een SORT_MERGE . gebruiken podium net als een $in vraag. Bijvoorbeeld:

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

heeft een bijna identiek zoekplan, indexgebruik en SORT_MERGE fase zoals in de $in voorbeeld hierboven. In wezen kan de vraag worden gezien als:

  • db.coll.find({a:1}).sort({b:1})
  • db.coll.find({a:3}).sort({b:1})
  • db.coll.find({a:5}).sort({b:1})
  • Neem de individuele zoekresultaten hierboven en voer een samenvoeging uit met de waarde b .

net als de $in voorbeeld eerder.

Echter, deze vraag:

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

kan geen enkele index gebruiken (aangezien we de {b:1} . niet hebben inhoudsopgave). Deze zoekopdracht zal resulteren in een collectiescan en bijgevolg heeft een sorteerfase in het geheugen omdat er geen index wordt gebruikt.

Als we echter de index {b:1} . maken , zal de zoekopdracht als volgt verlopen:

  • db.coll.find({a:1}).sort({b:1})
  • db.coll.find({b:1}).sort({b:1})
  • Neem de individuele zoekresultaten hierboven en voer een samenvoeging uit met de waarde b (die al is gesorteerd op beide subquery's, vanwege de indexen {a:1,b:1} en {b:1} ).

en MongoDB zal de resultaten van {a:1} . combineren en {b:1} query's en voer een samenvoeging uit op de resultaten. Het samenvoegingsproces is lineaire tijd, b.v. O(n) .

Tot slot, in een $or query, moet elke term een ​​index hebben, inclusief de sort() fase. Anders zal MongoDB een sortering in het geheugen moeten uitvoeren.




  1. Kan Hive niet verbinden met MongoDB met behulp van mongo-hadoop-connector

  2. hoe een geaggregeerde query in de mongodb-client op RockMongo of mViewer uit te voeren?

  3. Een dynamisch veld instellen in Ohm / Redis

  4. Spark en MongoDB-toepassing in Scala 2.10 maven ingebouwde fout