sql >> Databasteknik >  >> NoSQL >> MongoDB

Hur fungerar sortering med `$or` och `$in`-frågor i MongoDB?

Obs! Det här svaret är baserat på MongoDB 3.2.4.

Det är värt att upptäcka användningen av explain() i MongoDB. explain() utdata från en fråga (t.ex. db.collection.explain().find(...) ) låter dig kontrollera vilket index som används i en fråga och använda db.collection.explain('executionStats') kommer också att visa dig om frågan lyckas eller misslyckas på grund av SORT i minnet begränsning.

$in

En $in fråga kan ses som en serie jämställdhetsfrågor. Till exempel {a: {$in: [1,3,5]}} kan ses som {a:1}, {a:3}, {a:5} . MongoDB kommer att sortera $in array innan du fortsätter med frågan, så att {$in: [3,5,1]} är inte annorlunda än {$in: [1,3,5]} .

Låt oss anta att samlingen har ett index på

{a:1, b:1}
  • Sorterar efter a

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

    MongoDB kommer att kunna använda {a:1,b:1} index, eftersom den här frågan kan ses som en förening av {a:1}, {a:3}, {a:5} frågor. Sorterar efter {a:1} tillåter användning av indexprefix , så MongoDB behöver inte utföra en sortering i minnet.

    Samma situation gäller även för frågan:

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

    sedan sort({a:1}) använder också indexprefixet (a i detta fall), en SORT i minnet steg krävs därför inte.

  • Sorterar efter b

    Detta är ett mer intressant fall jämfört med att sortera efter a . Till exempel:

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

    explain() utdata från denna fråga kommer att ha ett steg som heter SORT_MERGE . Kom ihåg att find() del av frågan kan ses som {a:1}, {a:3}, {a:5} .

    Frågan db.coll.find({a:1}).sort({b:1}) behöver inte ha en SORT i minnet steg på grund av {a:1,b:1} karaktär index:det vill säga MongoDB kan helt enkelt gå igenom det (sorterade) indexet och returnera dokument sorterade efter b efter att ha uppfyllt likhetsparametern på a . Till exempel för varje a , det finns många b som redan är sorterade efter b på grund av indexet.

    Använder $in , kan den övergripande frågan ses som:

    • db.coll.find({a:1}).sort({b:1})
    • db.coll.find({a:3}).sort({b:1})
    • db.coll.find({a:5}).sort({b:1})
    • Ta de enskilda frågeresultaten ovan och utför en sammanslagning med värdet b . Frågan behöver inte ett sorteringssteg i minnet eftersom de individuella frågeresultaten redan är sorterade efter b . MongoDB behöver bara slå samman de (redan sorterade) sub-frågeresultaten till ett enda resultat.

    På samma sätt är frågan

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

    använder också en SORT_MERGE steg och är mycket lik frågan ovan. Skillnaden är att de enskilda frågorna matar ut dokument baserat på ett antal b (istället för varje b ) för varje a (som kommer att sorteras efter b på grund av indexet {a:1,b:1} ). Därför behöver frågan inte ett sorteringssteg i minnet.

$or

För en $or fråga om att använda ett index, varje klausul i $or uttryck måste ha ett index kopplat till sig . Om detta krav är uppfyllt är det möjligt för frågan att använda en SORT_MERGE steg precis som en $in fråga. Till exempel:

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

kommer att ha en nästan identisk frågeplan, indexanvändning och SORT_MERGE steg som i $in exemplet ovan. I huvudsak kan frågan ses som:

  • db.coll.find({a:1}).sort({b:1})
  • db.coll.find({a:3}).sort({b:1})
  • db.coll.find({a:5}).sort({b:1})
  • Ta de enskilda frågeresultaten ovan och utför en sammanslagning med värdet b .

precis som $in exempel tidigare.

Men den här frågan:

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

kan inte använda något index (eftersom vi inte har {b:1} index). Den här frågan kommer att resultera i en samlingsskanning och kommer därför att ha ett sorteringssteg i minnet eftersom inget index används.

Om vi ​​däremot skapar indexet {b:1} , kommer frågan att fortsätta så här:

  • db.coll.find({a:1}).sort({b:1})
  • db.coll.find({b:1}).sort({b:1})
  • Ta de enskilda frågeresultaten ovan och utför en sammanslagning med värdet b (vilket redan är sorterat vid båda underfrågorna, på grund av indexen {a:1,b:1} och {b:1} ).

och MongoDB kommer att kombinera resultaten av {a:1} och {b:1} frågor och utför en sammanslagning av resultaten. Sammanslagningsprocessen är linjär tid, t.ex. O(n) .

Sammanfattningsvis i en $or fråga måste varje term ha ett index, inklusive sort() skede. Annars måste MongoDB utföra en sortering i minnet.




  1. PHP startup mongo:Det går inte att initiera modulen

  2. Returnera specifik array från objektsamlingen

  3. Det går inte att ansluta Hive till MongoDB med mongo-hadoop-anslutningen

  4. doRedis med konstigt socket-anslutningsfel i Ubuntu Linux, R och RStudio