sql >> Database teknologi >  >> NoSQL >> MongoDB

Hvordan fungerer sortering med `$or` og `$in` forespørgsler i MongoDB?

Bemærk: Dette svar er baseret på MongoDB 3.2.4.

Det er umagen værd at opdage brugen af ​​explain() i MongoDB. explain() output af en forespørgsel (f.eks. db.collection.explain().find(...) ) giver dig mulighed for at kontrollere, hvilket indeks der bruges i en forespørgsel, og bruge db.collection.explain('executionStats') vil også vise dig, om forespørgslen lykkes eller mislykkes på grund af SORT i hukommelsen begrænsning.

$in

En $in forespørgsel kan opfattes som en serie af ligestillingsforespørgsler. For eksempel {a: {$in: [1,3,5]}} kunne opfattes som {a:1}, {a:3}, {a:5} . MongoDB vil sortere $in array, før du fortsætter med forespørgslen, så {$in: [3,5,1]} er ikke anderledes end {$in: [1,3,5]} .

Lad os antage, at samlingen har et indeks på

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

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

    MongoDB vil være i stand til at bruge {a:1,b:1} indeks, da denne forespørgsel kan opfattes som en forening af {a:1}, {a:3}, {a:5} forespørgsler. Sortering efter {a:1} tillader brug af indekspræfiks , så MongoDB behøver ikke at udføre en sortering i hukommelsen.

    Den samme situation gælder også for forespørgslen:

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

    siden sort({a:1}) bruger også indekspræfikset (a i dette tilfælde), en SORT i hukommelsen trin er derfor ikke påkrævet.

  • Sortering efter b

    Dette er et mere interessant tilfælde sammenlignet med sortering efter a . For eksempel:

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

    explain() output af denne forespørgsel vil have et trin kaldet SORT_MERGE . Husk at find() del af forespørgslen kan opfattes som {a:1}, {a:3}, {a:5} .

    Forespørgslen db.coll.find({a:1}).sort({b:1}) behøver ikke at have en SORT i hukommelsen trin på grund af arten af ​​{a:1,b:1} indeks:det vil sige, MongoDB kan simpelthen gå gennem (sorteret) indeks og returnere dokumenter sorteret efter b efter at have opfyldt lighedsparameteren på a . F.eks. for hver a , der er mange b som allerede er sorteret efter b på grund af indekset.

    Bruger $in , kan den overordnede forespørgsel opfattes 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})
    • Tag de individuelle forespørgselsresultater ovenfor, og udfør en fletning med værdien b . Forespørgslen behøver ikke et sorteringstrin i hukommelsen fordi de individuelle forespørgselsresultater allerede er sorteret efter b . MongoDB skal bare flette de (allerede sorterede) underforespørgselsresultater til et enkelt resultat.

    På samme måde er forespørgslen

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

    bruger også en SORT_MERGE fase og ligner meget forespørgslen ovenfor. Forskellen er, at de enkelte forespørgsler udskriver dokumenter baseret på en række af b (i stedet for hver b ) for hver a (som vil blive sorteret efter b på grund af indekset {a:1,b:1} ). Derfor behøver forespørgslen ikke et sorteringstrin i hukommelsen.

$or

For en $or forespørgsel om at bruge et indeks, hver klausul i $or udtryk skal have et indeks tilknyttet . Hvis dette krav er opfyldt, er det muligt for forespørgslen at anvende en SORT_MERGE trin ligesom en $in forespørgsel. For eksempel:

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

vil have en næsten identisk forespørgselsplan, indeksbrug og SORT_MERGE trin som i $in eksemplet ovenfor. Grundlæggende kan forespørgslen opfattes 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})
  • Tag de individuelle forespørgselsresultater ovenfor, og udfør en fletning med værdien b .

ligesom $in eksempel før.

Men denne forespørgsel:

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

kan ikke bruge noget indeks (da vi ikke har {b:1} indeks). Denne forespørgsel vil resultere i en samlingsscanning og vil have et sorteringstrin i hukommelsen da der ikke bruges noget indeks.

Hvis vi derimod opretter indekset {b:1} , vil forespørgslen fortsætte som:

  • db.coll.find({a:1}).sort({b:1})
  • db.coll.find({b:1}).sort({b:1})
  • Tag de individuelle forespørgselsresultater ovenfor, og udfør en fletning med værdien b (som allerede er sorteret ved begge underforespørgsler på grund af indekserne {a:1,b:1} og {b:1} ).

og MongoDB vil kombinere resultaterne af {a:1} og {b:1} forespørgsler og udføre en fletning af resultaterne. Sammenlægningsprocessen er lineær tid, f.eks. O(n) .

Afslutningsvis i en $or forespørgsel, skal hvert udtryk have et indeks, inklusive sort() scene. Ellers bliver MongoDB nødt til at udføre en sortering i hukommelsen.




  1. mongodb opdatering push array

  2. Udskrivning af en MongoDB-dato fra PHP

  3. MongDB kan ikke finde Promise type definition

  4. mongoDB, kunne ikke læse fra config-filen -- config i anden mappe / afinstallere den?