Cercherò di spiegare cosa significa questo con un esempio. Gli indici basati su B-tree non sono qualcosa di specifico di mongodb. Al contrario è un concetto piuttosto comune.
Quindi, quando crei un indice, mostri al database un modo più semplice per trovare qualcosa. Ma questo indice è memorizzato da qualche parte con un puntatore che punta a una posizione del documento originale. Questa informazione è ordinata e potresti vederla come un albero binario che ha una proprietà davvero interessante:la ricerca è ridotta da O(n)
(scansione lineare) su O(log(n))
. Il che è molto molto più veloce perché ogni volta dimezziamo il nostro spazio (potenzialmente possiamo ridurre il tempo da 10^6 a 20 ricerche). Ad esempio abbiamo una grande collezione con campo {a : some int, b: 'some other things'}
e se lo indicizziamo per a, finiamo con un'altra struttura di dati che è ordinata per a
. Sembra così (con questo non intendo che sia un'altra collezione, questo è solo a scopo dimostrativo):
{a : 1, pointer: to the field with a = 1}, // if a is the smallest number in the starting collection
...
{a : 999, pointer: to the field with a = 990} // assuming that 999 is the biggest field
Quindi in questo momento stiamo cercando un campo a =18. Invece di passare uno per uno attraverso tutti gli elementi prendiamo qualcosa nel mezzo e se è più grande di 18, allora dividiamo la parte inferiore a metà e controlliamo l'elemento lì . Continuiamo finché non troveremo a =18. Quindi osserviamo il puntatore e sapendolo estraiamo il campo originale.
La situazione con l'indice composto è simile (invece di ordinare per un elemento, ordiniamo per molti). Ad esempio hai una collezione:
{ "item": 5, "location": 1, "stock": 3, 'a lot of other fields' } // was stored at position 5 on the disk
{ "item": 1, "location": 3, "stock": 1, 'a lot of other fields' } // position 1 on the disk
{ "item": 2, "location": 5, "stock": 7, 'a lot of other fields' } // position 3 on the disk
... huge amount of other data
{ "item": 1, "location": 1, "stock": 1, 'a lot of other fields' } // position 9 on the disk
{ "item": 1, "location": 1, "stock": 2, 'a lot of other fields' } // position 7 on the disk
e vuoi un indice { "item":1, "location":1, "stock":1 }. La tabella di ricerca sarebbe simile a questa (ancora una volta - questa non è un'altra raccolta, è solo a scopo dimostrativo):
{ "item": 1, "location": 1, "stock": 1, pointer = 9 }
{ "item": 1, "location": 1, "stock": 2, pointer = 7 }
{ "item": 1, "location": 3, "stock": 1, pointer = 1 }
{ "item": 2, "location": 5, "stock": 7, pointer = 3 }
.. huge amount of other data (but not necessarily here. If item would be one it would be somewhere next to items 1)
{ "item": 5, "location": 1, "stock": 3, pointer = 5 }
Vedi che qui tutto è fondamentalmente ordinato per elemento, quindi per posizione e quindi per puntatore. Allo stesso modo di un singolo indice, non abbiamo bisogno di scansionare tutto. Se abbiamo una query che cerca item = 2, location = 5 and stock = 7
possiamo identificare rapidamente dove i documenti con item = 2
sono e quindi allo stesso modo identificare rapidamente dove tra questi elementi l'articolo con location 5
e così via.
E in questo momento una parte interessante . Inoltre abbiamo creato un solo indice (sebbene questo sia un indice composto, è comunque un indice) possiamo usarlo per trovare rapidamente l'elemento
- solo dall'
item
. Davvero tutto ciò che dobbiamo fare è solo il primo passo. Quindi non ha senso creare un altro indice {location :1} perché è già coperto da un indice composto. - inoltre possiamo trovare rapidamente solo per
item and by location
(abbiamo bisogno solo di 2 passaggi).
Cool 1 index ma ci aiuta in tre modi diversi. Ma aspetta un minuto:e se volessimo trovare per item and stock
. Oh, sembra che possiamo velocizzare anche questa query. Possiamo in log(n) trovare tutti gli elementi con un oggetto specifico e ... qui dobbiamo fermarci:la magia è finita. Abbiamo bisogno di scorrere tutti loro. Ma comunque abbastanza buono.
Ma possa aiutarci con altre domande. Diamo un'occhiata a una query per location
che sembra già ordinato. Ma se lo guardi, vedi che questo è un pasticcio. Uno all'inizio e poi uno alla fine. Non può aiutarti affatto.
Spero che questo chiarisca alcune cose:
- perché gli indici sono buoni (ridurre il tempo da O(n) a potenzialmente O(log(n))
- perché gli indici composti possono essere utili con alcune query, tuttavia non abbiamo creato un indice su quel campo particolare e aiutano con altre query.
- quali indici sono coperti dall'indice composto
- perché gli indici possono danneggiare (crea una struttura dati aggiuntiva che dovrebbe essere mantenuta)
E questo dovrebbe dire un'altra cosa valida:l'indice è non un proiettile d'argento . Non puoi velocizzare tutte le tue query, quindi sembra sciocco pensare che creando indici su tutti i campi TUTTO sarebbe super veloce.