Indexy v MongoDB jsou uloženy ve struktuře B-stromu, kde každá položka indexu ukazuje na konkrétní místo na disku. Použití struktury B-stromu také znamená, že index MongoDB je uložen v seřazeném pořadí, vždy se projde v daném pořadí a pro MongoDB je levné načíst sérii dokumentů v seřazeném pořadí prostřednictvím indexů.
Aktualizovat :Struktura B-stromu platí pro úložiště MMAPv1, ale je implementována mírně odlišně pomocí úložiště WiredTiger (výchozí od MongoDB 3.2). Základní myšlenka zůstává stejná, kdy je levné procházet index v seřazeném pořadí.
A SORT
fáze (tj. řazení v paměti) v dotazu je omezena na 32 MB využití paměti. Dotaz se nezdaří, pokud SORT
etapa tuto hranici překračuje. Tento limit lze obejít využitím setříděné povahy indexů, takže MongoDB může vrátit dotaz s sort()
parametr bez provedení řazení v paměti.
Předpokládejme, že dotaz má tvar:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort(...)
s kolekcí a
s indexem:
db.a.createIndex({b:1,c:1})
Existují dva možné scénáře, kdy sort()
fáze je uvedena v dotazu:
1. MongoDB nemůže použít seřazenou povahu indexu a musí provést v paměti SORT
etapa .
Toto je výsledek, pokud dotaz nemůže použít "prefix indexu". Například:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort({c:1})
V dotazu výše index {b:1,c:1}
lze použít k:
- Přiřaďte dokumenty obsahující
b
větší než 100 pro{b:{$gt:100}}
část dotazu. - Nicméně není zaručeno, že vrácené dokumenty jsou seřazeny podle
c
.
Proto MongoDB nemá jinou možnost, než provést řazení v paměti. explain()
výstup tohoto dotazu bude mít SORT
etapa. Toto SORT
etapa by byla omezena na 32 MB využití paměti.
2. MongoDB může využívat tříděný charakter indexu .
Toto je výsledek, pokud dotaz používá:
- Klíče řazení, které odpovídá pořadí indexu, a
- Určuje stejné pořadí jako index (tj. index
{b:1,c:1}
lze použít prosort({b:1,c:1})
nebosort({b:-1,c:-1})
ale nesort({b:1,c:-1})
)
Například:
db.a.find({b:{$gt:100}, c:{$gt:200}}).sort({b:1})
V dotazu výše index {b:1,c:1}
lze použít k:
- Přiřaďte dokumenty obsahující
b
větší než 100 pro{b:{$gt:100}}
část dotazu. - V tomto případě MongoDB může zaručit, že vrácené dokumenty jsou seřazeny podle
b
.
explain()
výstup výše uvedeného dotazu nebude mít SORT
etapa. Také funkce explain()
výstup dotazu s a bez sort()
jsou identické . V podstatě dostáváme sort()
zdarma.
Cenným zdrojem pro pochopení tohoto tématu je Optimalizace složených indexů MongoDB. Vezměte prosím na vědomí, že tento blogový příspěvek byl napsán již v roce 2012. Ačkoli některá terminologie může být zastaralá, technická stránka příspěvku je stále relevantní.
Aktualizace doplňujících otázek
-
MongoDB používá pro většinu dotazů pouze jeden index. Chcete-li se například vyhnout v paměti
SORT
fázi v dotazudb.a.find({a:1}).sort({b:1})
index musí pokrývat obě
a
ab
pole současně; např. složený index, například{a:1,b:1}
je požadováno. Nemůžete mít dva samostatné indexy{a:1}
a{b:1}
a očekávejte{a:1}
index, který se má použít pro část rovnosti, a{b:1}
index, který se má použít pro třídicí část. V tomto případě si MongoDB vybere jeden ze dvou indexů.Proto je správné, že jsou výsledky seřazeny, protože jsou vyhledány a vráceny v pořadí podle indexu.
-
Chcete-li se vyhnout řazení v paměti pomocí složeného indexu, první část indexu musí odpovídat části rovnosti dotazu a druhá část musí odpovídat třídění dotazu (jak je uvedeno ve vysvětlení pro (1) výše).
Pokud máte dotaz jako je tento:
db.a.find({}).sort({a:1})
index
{a:1,b:1}
lze použít pro třídící část (protože v podstatě vracíte celou kolekci). A pokud váš dotaz vypadá takto:db.a.find({a:1}).sort({b:1})
stejný index
{a:1,b:1}
lze také použít pro obě části dotazu. Také:db.a.find({a:1,b:1})
může také použít stejný index
{a:1,b:1}
Všimněte si vzoru zde:
find()
následujesort()
parametry sledují pořadí indexu{a:1,b:1}
. Složený index proto musí být uspořádán podle rovnosti -> řazení .
Aktualizace týkající se řazení různých typů
Pokud má pole mezi dokumenty různé typy (např. pokud a
je řetězec v jednom dokumentu, číslo v ostatních, booleovský v dalším), jak probíhá řazení?
Odpověď je pořadí porovnání typu MongoDB BSON. Abychom parafrázovali manuálovou stránku, pořadí je:
- MinKey (interní typ)
- Nulé
- Čísla (ints, longs, double, desetinná místa)
- Symbol, řetězec
- Objekt
- Pole
- BinData
- ObjectId
- Booleovská hodnota
- Datum
- Časové razítko
- Regulární výraz
- MaxKey (interní typ)
Takže z výše uvedeného příkladu s použitím vzestupného pořadí se nejprve zobrazí dokumenty obsahující čísla, poté řetězce a poté boolean.