L'index devrait couvrir toutes les parties de la requête (partie égalité, partie tri et partie plage). C'est parce que dans un find()
typique requête, MongoDB n'utilise qu'un seul index. Par exemple, il n'utilise généralement pas un index pour la partie égalité et un autre index pour la partie tri.
En général, la séquence des champs dans l'index doit suivre le modèle égalité -> tri -> plage .
Ceci est décrit en détail dans Optimisation des index composés MongoDB .
Pour votre requête, la partie égalité est tag:..., letterId:...
et la partie tri est emailId:-1
. Il n'y a pas de plage dans votre requête.
En utilisant ce modèle, l'index composé dont vous avez besoin est :
db.test.createIndex({tag:1, letterId:1, emailId:-1})
Essayons de confirmer l'amélioration des performances que nous pouvons obtenir en utilisant cet index.
Données de test
Pour confirmer la pertinence de l'index, j'ai inséré 1 million d'enregistrements dans une base de données de test en utilisant mgeneratejs , qui est un outil pour créer un document aléatoire à l'aide d'un modèle.
Sur la base de votre exemple, le mgeneratejs
modèle que j'utilise est :
$ 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}}}}
}
et importé 1 million de documents aléatoires dans MongoDB :
$ mgeneratejs template.json -n 1000000 | mongoimport -d test -c test
Test 1 :indice non optimal
Ensuite, je crée l'index que vous avez, et j'ai essayé de trouver un document inexistant et j'ai rassemblé 10 exécutions de la requête avec la collection contenant uniquement cet index :
> 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
donc en utilisant cet index, les temps de réponse de la requête ne sont pas excellents, avec la plupart des exécutions proches de 3 secondes.
Test 2 :égalité -> tri -> index de plage
En ajoutant l'optimum equality -> sort -> range 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
En revanche, en utilisant l'indice optimal, les performances ont été nettement améliorées. Aucune requête n'est retournée en plus de 3 ms, avec la grande majorité du temps, elle revient en 1 ms.