Indexen in MongoDB worden opgeslagen in een B-boomstructuur, waarbij elke indexingang verwijst naar een specifieke locatie op de schijf. Het gebruik van een B-tree-structuur betekent ook dat een MongoDB-index in een gesorteerde volgorde wordt opgeslagen, altijd in volgorde wordt doorlopen, en dat het voor MongoDB goedkoop is om een reeks documenten in een gesorteerde volgorde via indexen op te halen.
Bijwerken :De B-tree-structuur is waar voor de MMAPv1-opslagengine, maar wordt iets anders geïmplementeerd door de WiredTiger-opslagengine (standaard sinds MongoDB 3.2). Het basisidee blijft hetzelfde, waarbij het goedkoop is om de index in een gesorteerde volgorde te doorlopen.
Een SORT
fase (d.w.z. in-memory sort) in een query is beperkt tot 32 MB geheugengebruik. Een zoekopdracht zal mislukken als de SORT
stadium deze grens overschrijdt. Deze limiet kan worden omzeild door gebruik te maken van de gesorteerde aard van indexen, zodat MongoDB een query kan retourneren met een sort()
parameter zonder een sortering in het geheugen uit te voeren.
Laten we aannemen dat de query de vorm heeft:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort(...)
met verzameling a
met een index van:
db.a.createIndex({b:1,c:1})
Er zijn twee mogelijke scenario's wanneer een sort()
fase is gespecificeerd in de query:
SORT
uitvoeren podium .
Dit is het resultaat als de query de "index prefix" niet kan gebruiken. Bijvoorbeeld:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort({c:1})
In de bovenstaande zoekopdracht is de index {b:1,c:1}
kan worden gebruikt om:
- Overeenkomen met documenten met
b
groter dan 100 voor de{b:{$gt:100}}
gedeelte van de zoekopdracht. - Echter, er is geen garantie dat de geretourneerde documenten zijn gesorteerd in termen van
c
.
Daarom heeft MongoDB geen andere keuze dan een in-memory sortering uit te voeren. De explain()
uitvoer van deze zoekopdracht heeft een SORT
fase. Deze SORT
stage zou beperkt zijn tot 32 MB geheugengebruik.
Dit is het resultaat als de zoekopdracht het volgende gebruikt:
- Sorteersleutels die overeenkomen met de volgorde van de index, en
- Specificeert dezelfde volgorde als de index (d.w.z. de index
{b:1,c:1}
kan worden gebruikt voorsort({b:1,c:1})
ofsort({b:-1,c:-1})
maar nietsort({b:1,c:-1})
)
Bijvoorbeeld:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort({b:1})
In de bovenstaande zoekopdracht is de index {b:1,c:1}
kan worden gebruikt om:
- Overeenkomen met documenten met
b
groter dan 100 voor de{b:{$gt:100}}
gedeelte van de zoekopdracht. - In dit geval kan MongoDB garanderen dat de geretourneerde documenten worden gesorteerd in termen van
b
.
De explain()
uitvoer van de bovenstaande zoekopdracht zal niet hebben een SORT
fase. Ook de explain()
uitvoer van de query met en zonder sort()
zijn identiek . In wezen krijgen we de sort()
gratis.
Een waardevolle bron om dit onderwerp te begrijpen, is het optimaliseren van MongoDB-samengestelde indexen. Houd er rekening mee dat deze blogpost al in 2012 is geschreven. Hoewel een deel van de terminologie misschien verouderd is, is de technische aard van de post nog steeds relevant.
Update op vervolgvragen
-
MongoDB gebruikt slechts één index voor de meeste zoekopdrachten. Dus om bijvoorbeeld een in-memory
SORT
. te vermijden fase in de zoekopdrachtdb.a.find({a:1}).sort({b:1})
de index moet zowel
a
. dekken enb
velden tegelijkertijd; bijv. een samengestelde index zoals{a:1,b:1}
Is benodigd. U kunt geen twee afzonderlijke indexen hebben{a:1}
en{b:1}
, en verwacht de{a:1}
index die moet worden gebruikt voor het gelijkheidsgedeelte, en de{b:1}
index die moet worden gebruikt voor het sorteergedeelte. In dit geval zal MongoDB een van de twee indexen kiezen.Daarom is het juist dat de resultaten worden gesorteerd omdat ze worden opgezocht en geretourneerd in de volgorde van de index.
-
Om te voorkomen dat er in het geheugen wordt gesorteerd met een samengestelde index, moet het eerste deel van de index het gelijkheidsgedeelte bevatten van de zoekopdracht, en het tweede deel moet voldoen aan het sorteergedeelte van de zoekopdracht (zoals weergegeven in de uitleg voor (1) hierboven).
Als je een vraag als deze hebt:
db.a.find({}).sort({a:1})
de index
{a:1,b:1}
kan worden gebruikt voor het sorteergedeelte (aangezien je in feite de hele verzameling retourneert). En als uw zoekopdracht er als volgt uitziet:db.a.find({a:1}).sort({b:1})
dezelfde index
{a:1,b:1}
kan ook voor beide delen van de query worden gebruikt. Ook:db.a.find({a:1,b:1})
kan ook dezelfde index gebruiken
{a:1,b:1}
Let hier op het patroon:de
find()
gevolgd doorsort()
parameters volgen de indexvolgorde{a:1,b:1}
. Daarom moet een samengestelde index worden geordend op gelijkheid -> sorteren .
Update met betrekking tot het sorteren van verschillende typen
Als een veld verschillende typen heeft tussen documenten (bijv. als a
is string in het ene document, nummer in andere, boolean in weer een ander), hoe verloopt de sortering?
Het antwoord is MongoDB BSON-type vergelijkingsvolgorde. Om de handleiding te parafraseren, is de volgorde:
- MinKey (intern type)
- Null
- Getallen (ints, longs, doubles, decimals)
- Symbool, tekenreeks
- Object
- Array
- BinData
- Object-ID
- Booleaans
- Datum
- Tijdstempel
- Regelmatige expressie
- MaxKey (intern type)
Dus uit het bovenstaande voorbeeld met oplopende volgorde, verschijnen eerst documenten met getallen, dan tekenreeksen en dan booleaans.