web-dev-qa-db-fra.com

MongoDB Find performance: index composé unique VS deux index champ unique

Je cherche un conseil sur la stratégie d'indexation à utiliser dans MongoDb 3.4.

Supposons que nous ayons une collection de documents people avec la forme suivante:

{
    _id: 10,
    name: "Bob",
    age: 32,
    profession: "Hacker"
}

Imaginons qu'une API Web pour interroger la collection soit exposée et que les seuls filtres possibles soient par nom ou par âge .
Un exemple d'appel à l'API sera quelque chose comme: http://myAwesomeWebSite/people?name="Bob"&age=25

Un tel appel sera traduit dans la requête suivante: db.people.find({name: "Bob", age: 25}).

Pour mieux clarifier notre scénario, considérons que:

  • le nom du champ était déjà dans nos documents et nous avons déjà un index sur ce champ
  • nous allons ajouter le nouveau champ age en raison de certaines nouvelles fonctionnalités de notre application
  • la base de données n'est accessible que via l'api web mentionnée ci-dessus et l'exigence la plus importante est d'exposer une api web super rapide
  • tous les appels à l'API Web appliqueront un filtre à la fois sur le nom et l'âge des champs (autrement dit, tous les appels à l'API Web auront le même modèle, qui est celui montré ci-dessus)

Cela dit, nous devons décider lequel des index suivants offre les meilleures performances:

  • Un index composé: {name: 1, age: 1}
  • Deux index à champ unique: {name: 1} Et {age: 1}

Selon certains tests simples, il semble que l'indice composé unique est beaucoup plus performant que les deux indices à champ unique.

En exécutant une seule requête via le mongo Shell, la méthode expl () suggère qu'en utilisant un seul index composé, vous pouvez interroger la base de données presque dix fois plus rapidement qu'en utilisant deux index de champs uniques.

Cette différence semble moins dramatique dans un scénario plus réaliste, où au lieu d'exécuter une seule requête via le mongo Shell, plusieurs appels sont effectués vers deux URL différentes d'une application Web nodejs. Les deux URL exécutent une requête dans la base de données et renvoient les données récupérées sous forme de tableau json, l'une utilisant une collection avec l'index composé unique et l'autre utilisant une collection avec deux index à champ unique (les deux collections ayant exactement les mêmes documents).
Dans ce test, l'indice composé unique semble toujours être le meilleur choix en termes de performances, mais cette fois la différence est moins marquée.

Selon les résultats des tests, nous envisageons d'utiliser l'approche à indice composé unique.

Quelqu'un a-t-il de l'expérience sur ce sujet? Sommes-nous en train de manquer une considération importante (peut-être un inconvénient des grands indices composés)?

22
Enrico Massone

Étant donné une requête standard simple (sans limit() ou sort() ou quoi que ce soit de fantaisiste appliqué) qui a une condition de filtre sur deux champs (comme dans name et age dans votre exemple), afin de trouver les documents résultants, MongoDB:

  1. faire une analyse complète de la collection (lire tous les documents de la collection entière, analyser le BSON, trouver les valeurs en question, les tester par rapport à l'entrée et retourner/jeter chaque document): il s'agit d'une super E/S intense et donc lente.
  2. utilisez un index qui contient l'un des champs (utilisez l'arborescence d'index pour localiser un sous-ensemble de documents pertinent suivi d'une analyse de ceux-ci): Selon votre distribution de données/index sélectivité cela peut être très rapide ou n'apporter pratiquement aucun avantage (imaginez un index sur age dans un ensemble de données de millions de personnes entre 30 et 40 ans -> chaque recherche serait toujours produire un nombre infini de documents).
  3. utilisez deux index qui contiennent ensemble les deux champs en question (chargez les deux index, effectuez des recherches de clés, puis calculez le intersection du résultats): Encore une fois, en fonction de la distribution de vos données, cela peut ou non vous donner de grandes (er) performances. Il devrait cependant, dans la plupart des cas, être plus rapide que # 2. Je serais cependant surpris s'il était vraiment 10 fois plus lent que le n ° 4 (comme vous l'avez mentionné).
  4. utiliser un indice composé (deux recherches de clés ultérieures conduisent immédiatement aux documents requis): Ce sera l'option la plus rapide de toutes étant donné qu'il faut les opérations les moins coûteuses pour obtenir les bons documents. Afin d'assurer le plus haut niveau de réutilisation (pas des performances qui ne seront pas affectées par cela), vous devez en général commencer par le champ le plus sélectif en premier, donc dans votre cas probablement name et non age étant donné que beaucoup de gens auront le même age (si faible sélectivité) par rapport à name (sélectivité plus élevée). Mais ce choix dépend également de votre scénario concret et des requêtes que vous comptez exécuter sur votre base de données. Il existe un très bon article sur le Web sur la meilleure façon de définir un indice composé en tenant compte de divers aspects de votre situation spécifique: https://emptysqua.re/blog/optimizing-mongodb-compound-indexes =

Les autres aspects à considérer sont les suivants: Les mises à jour de l'indice ont un certain prix. Cependant, si tout ce qui vous intéresse est la vitesse de lecture brute et que vous n'avez que quelques mises à jour de temps en temps, alors vous devriez opter pour des index plus/plus grands.

Et le dernier mais non le moindre (!) Le conseil de base bien utilisé: profilez l'enfer de votre système en utilisant des données réelles et peut-être même des scénarios de charge réalistes. Et continuez également à mesurer au fur et à mesure que vos données/système évoluent.

Lectures supplémentaires: https://docs.mongodb.com/manual/core/query-optimization/index.html

https://dba.stackexchange.com/questions/158240/mongodb-index-intersection-does-not- éliminate-the-need-for-creating-compound-in

Index intersection vs index composé?

mongodb compund index vs. index intersect

Comment l'ordre des index composés importe-t-il dans MongoDB en termes de performances?

Dans MongoDB, j'utilise une grande requête, comment je vais créer un index composé ou un index unique, donc mon temps de réponse augmente

26
dnickless