L'indice dovrebbe coprire tutta la parte della query (parte di uguaglianza, parte di ordinamento e parte di intervallo). Questo perché in un tipico find()
query, MongoDB utilizza solo un indice. Ad esempio, generalmente non utilizza un indice per la parte di uguaglianza e un altro indice per la parte di ordinamento.
In generale, la sequenza dei campi nell'indice deve seguire lo schema di uguaglianza -> ordinamento -> intervallo .
Questo è descritto in dettaglio in Ottimizzazione degli indici composti MongoDB .
Per la tua query, la parte di uguaglianza è tag:..., letterId:...
e la parte di ordinamento è emailId:-1
. Non c'è alcuna parte di intervallo nella tua query.
Utilizzando questo modello, l'indice composto di cui hai bisogno è:
db.test.createIndex({tag:1, letterId:1, emailId:-1})
Proviamo a confermare quanto miglioramento delle prestazioni possiamo ottenere utilizzando questo indice.
Dati di prova
Per confermare l'idoneità dell'indice, ho inserito 1 milione di record in un database di test utilizzando mgeneratejs , che è uno strumento per creare un documento casuale utilizzando un modello.
Sulla base del tuo esempio, mgeneratejs
il modello che sto usando è:
$ cat template.json
{
"emailId": "$hash",
"email": "$email",
"letterId": "$hash",
"sendedFrom": "$email",
"resultMsg": "$word",
"owner": "$name",
"created": "$date",
"result": "$bool",
"tag": "$word",
"tryNum": {"$integer": {"min": 0, "max": 1e3}},
"clickHash": "$word",
"links": {"$array": {"of": "$url", "number": {"$integer": {"min": 1, "max": 5}}}}
}
e importato 1 milione di documenti casuali in MongoDB:
$ mgeneratejs template.json -n 1000000 | mongoimport -d test -c test
Test 1:indice non ottimale
Quindi creo l'indice che hai e provo a trovare un documento inesistente e raccolgo 10 esecuzioni della query con la raccolta contenente solo questo indice:
> db.test.createIndex({emailId: 1, letterId: 1, result: 1, owner: 1, tag: 1, clickHash: 1})
> db.test.find({"tag" : "xyz", "letterId" : "abc"}).sort({emailId: -1}).limit(1)
Fetched 0 record(s) in 3069ms
Fetched 0 record(s) in 2924ms
Fetched 0 record(s) in 2923ms
Fetched 0 record(s) in 3013ms
Fetched 0 record(s) in 2917ms
Fetched 0 record(s) in 2961ms
Fetched 0 record(s) in 2882ms
Fetched 0 record(s) in 2870ms
Fetched 0 record(s) in 2969ms
Fetched 0 record(s) in 2863ms
quindi usando quell'indice, i tempi di risposta della query non sono ottimi, con la maggior parte dell'esecuzione vicino a 3 secondi.
Test 2:uguaglianza -> ordinamento -> indice intervallo
Aggiungendo l'uguaglianza -> ordinamento -> intervallo ottimale indice:
> db.test.createIndex({tag:1, letterId:1, emailId:-1})
> db.test.find({"tag" : "xyz", "letterId" : "abc"}).sort({emailId: -1}).limit(1)
Fetched 0 record(s) in 2ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 3ms
Al contrario, utilizzando l'indice ottimale, la performance è stata notevolmente migliorata. Nessuna query restituita in più di 3 ms, la maggior parte delle volte viene restituita in 1 ms.