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

Indici composti MongoDB - L'ordinamento è importante?

Puoi pensare all'indice a campo singolo MongoDB come a un array, con puntatori alle posizioni dei documenti. Ad esempio, se hai una collezione con (nota che la sequenza è deliberatamente fuori ordine):

[collection]
1: {a:3, b:2}
2: {a:1, b:2}
3: {a:2, b:1}
4: {a:1, b:1}
5: {a:2, b:2}

Indice a campo singolo

Ora se lo fai:

db.collection.createIndex({a:1})

L'indice è approssimativamente simile a:

[index a:1]
1: {a:1} --> 2, 4
2: {a:2} --> 3, 5
3: {a:3} --> 1

Nota tre cose importanti:

  • È ordinato per a ascendente
  • Ogni ingresso punta al luogo in cui risiedono i documenti pertinenti
  • L'indice registra solo i valori di a campo. Il b il campo non esiste affatto nell'indice

Quindi, se fai una query come:

db.collection.find().sort({a:1})

Tutto quello che deve fare è percorrere l'indice dall'alto verso il basso, prelevare ed emettere il documento indicato dalle voci. Nota che puoi anche percorrere l'indice dal basso, ad esempio:

db.collection.find().sort({a:-1})

e l'unica differenza è che percorri l'indice al contrario.

Perché b non è affatto nell'indice, non puoi usare l'indice quando esegui query su b .

Indice composto

In un indice composto es.:

db.collection.createIndex({a:1, b:1})

Significa che vuoi ordinare per a prima, quindi ordina per b . L'indice sarebbe simile a:

[index a:1, b:1]
1: {a:1, b:1} --> 4
2: {a:1, b:2} --> 2
3: {a:2, b:1} --> 3
4: {a:2, b:2} --> 5
5: {a:3, b:2} --> 1

Nota che:

  • L'indice è ordinato da a
  • All'interno di ogni a hai un b ordinato
  • Hai 5 voci di indice rispetto alle sole tre del precedente esempio a campo singolo

Usando questo indice, puoi eseguire una query come:

db.collection.find({a:2}).sort({b:1})

Può facilmente trovare dove a:2 quindi sposta l'indice in avanti. Dato quell'indice, non puoi farlo :

db.collection.find().sort({b:1})
db.collection.find({b:1})

In entrambe le query non puoi trovare facilmente b poiché è distribuito in tutto l'indice (cioè non in voci contigue). Comunque tu puoi fare:

db.collection.find({a:2}).sort({b:-1})

poiché puoi essenzialmente trovare dove si trova a:2 sono e percorri il b voci indietro.

Modifica :chiarimento della domanda di @marcospgp nel commento:

La possibilità di utilizzare l'indice {a:1, b:1} per soddisfare find({a:2}).sort({b:-1}) in realtà ha senso se lo vedi da un punto di vista della tabella ordinata. Ad esempio, l'indice {a:1, b:1} può essere pensato come:

a | b
--|--
1 | 1
1 | 2
2 | 1
2 | 2
2 | 3
3 | 1
3 | 2

trova({a:2}).sort({b:1})

L'indice {a:1, b:1} significa sort by a, then within each a, sort the b values . Se poi esegui un find({a:2}).sort({b:1}) , l'indice sa dove si trovano tutti i a=2 sono. All'interno di questo blocco di a=2 , il b verrebbe ordinato in ordine crescente (secondo le specifiche dell'indice), in modo che la query find({a:2}).sort({b:1}) può essere soddisfatto da:

a | b
--|--
1 | 1
1 | 2
2 | 1 <-- walk this block forward to satisfy
2 | 2 <-- find({a:2}).sort({b:1})
2 | 3 <--
3 | 1
3 | 2

trova({a:2}).sort({b:-1})

Poiché l'indice può essere percorso avanti o indietro, è stata seguita una procedura simile, con una piccola svolta alla fine:

a | b
--|--
1 | 1
1 | 2
2 | 1  <-- walk this block backward to satisfy
2 | 2  <-- find({a:2}).sort({b:-1})
2 | 3  <--
3 | 1
3 | 2

Il fatto che l'indice possa essere percorso avanti o indietro è il punto chiave che abilita la query find({a:2}).sort({b:-1}) per poter utilizzare l'indice {a:1, b:1} .

Spiegazione del pianificatore di query

Puoi vedere cosa pianifica il pianificatore di query utilizzando db.collection.explain().find(....) . Fondamentalmente se vedi uno stage di COLLSCAN , nessun indice è stato utilizzato o può essere utilizzato per la query. Vedi spiega i risultati per i dettagli sull'output del comando.