MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

La requête Mongo prend beaucoup de temps. Comment le rendre plus rapide ?

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.