Créez des index efficaces dans ApsaraDB for MongoDB en analysant leur efficacité, en choisissant le type approprié et en les optimisant pour des requêtes spécifiques.
Choix d'un index
ApsaraDB for MongoDB prend en charge plusieurs types d'index. Sélectionnez le type adapté à votre scénario.
-
Utilisez des index à clé unique
Si toutes vos requêtes utilisent une seule clé, créez un index à clé unique.
-
Utilisez des index composites
Si vos requêtes combinent des conditions sur une ou plusieurs clés, créez un index composite prenant en charge jusqu'à 32 clés. L'exemple suivant crée un index composite sur les champs
categoryetitem.db.products.createIndex( { "category": 1, "item": 1 } ) -
Utilisez des index de texte
Un index classique correspond à la valeur exacte d'un champ. Pour rechercher des mots spécifiques dans un champ de texte volumineux, utilisez un index de texte. Pour plus d'informations, consultez Text Indexes on Self-Managed Deployments.
Spécification des collations d'index
Pour exploiter les index lors de comparaisons de chaînes, spécifiez la même collation pour l'index et les opérations de requête. Les index dotés d'une collation spécifique ne prennent pas en charge les requêtes utilisant une collation différente.
L'exemple suivant présente une collection avec un index sur le champ de chaîne myColl. L'index utilise la locale de collation category "fr" :
db.myColl.createIndex( { category: 1 }, { collation: { locale: "fr" } } )
Spécifiez la même collation que celle de l'index pour utiliser ce dernier lors de l'opération de requête suivante :
db.myColl.find( { category: "cafe" } ).collation( { locale: "fr" } )
L'opération de requête suivante utilise la collation binaire par défaut "simple" et ne peut pas exploiter l'index :
db.myColl.find( { category: "cafe" } )
Pour les index composites dont les clés de préfixe ne sont ni une chaîne, ni un tableau, ni un document imbriqué, les opérations de requête spécifiant une collation différente peuvent toujours utiliser l'index pour les comparaisons sur les clés de préfixe. Pour plus d'informations sur les collations, consultez Collation Locales and Default Parameters.
Analyse des index via les journaux de requêtes lentes
ApsaraDB for MongoDB optimise les index afin de réduire le nombre de documents analysés. Concentrez-vous sur les métriques DocsExamined et KeysExamined dans les journaux de requêtes lentes. Pour savoir comment afficher ces journaux, consultez Afficher les journaux de requêtes lentes.
DocsExamined: nombre de documents analysés pour une requête. Une valeur élevée indique que de nombreuses entrées non indexées sont parcourues. Créez un index sur les champs interrogés pour réduire ce nombre.KeysExamined: nombre de clés d'index analysées. Si cette valeur est élevée alors quenreturnedest faible, l'index est inefficace. Ajustez l'index ou créez-en un plus sélectif.
La logique d'analyse des index s'applique comme suit :
-
Analyse complète de la collection (mots-clés :
COLLSCANetDocsExamined)COLLSCANindique une analyse complète de la collection. Si ce mot-clé apparaît dans les journaux de requêtes lentes après une opération de lecture, de mise à jour ou de suppression, créez des index sur les champs interrogés.DocsExaminedindique le nombre de documents analysés pour une requête. Plus la valeur est élevée, plus la consommation de ressources CPU est importante.
-
Index inappropriés (mots-clés :
IXSCANetkeysExamined)keysExaminedindique le nombre de clés d'index analysées. Plus la valeur est élevée, plus la consommation de ressources CPU est importante.Un index inapproprié, ou correspondant à trop de données, ne réduit pas la surcharge CPU ni n'accélère les requêtes.
Si vous repérez le mot-clé
SORTdans les journaux de requêtes lentes, utilisez un index pour optimiser les performances de tri. Pour plus d'informations, consultez The ESR (Equality, Sort, Range) Rule.
Optimisation des index
Utilisation des requêtes couvertes
Une requête couverte renvoie les résultats directement depuis l'index sans accéder au document source. Pour déterminer si une requête est couverte, utilisez la commande explain(). Si la sortie de explain() indique que totalDocsExamined est égal à 0, la requête est couverte par l'index.
Si la sortie de explain() ne contient pas le champ totalDocsExamined, exécutez la requête en mode executionStats ou allPlansExecution. Par exemple, utilisez explain("executionStats") ou explain("allPlansExecution").
Lors de l'implémentation d'une requête couverte, le champ _id est renvoyé par défaut. Excluez-le explicitement des résultats de la requête ou ajoutez-le à l'index.
Dans un cluster shardé, MongoDB doit accéder en interne aux champs de clé de sharding. Pour qu'une requête soit couverte, la clé de sharding doit faire partie de l'index. Il est donc recommandé d'inclure la clé de sharding dans vos index.
Suppression des index redondants
Les index consomment de la RAM et de l'espace disque, même avec la compression WiredTiger. La mise à jour des champs indexés ajoute également une surcharge CPU et d'E/S disque. Évaluez soigneusement et supprimez les index devenus inutiles.
Recommandations pour les index composites
Pour une requête composite sur plusieurs champs, l'ordre des champs dans la requête n'a pas d'importance. Un seul index suffit. Par exemple, pour une requête sur les champs
aetb, vous n'avez besoin que de l'un des index suivants :{a:1, b:1}ou{b:1, a:1}.-
Des index redondants peuvent résulter d'une relation d'inclusion. Par exemple, considérez les requêtes suivantes :
db.myCol.find({"b": 2, "c": 3})db.myCol.find({"a": 1, "b": 2, "c": 3})
La deuxième requête contient tous les champs de la première. Un seul index peut satisfaire les deux requêtes. Placez les champs de la requête la plus spécifique au début de l'index. L'index devrait être
{b: 1, c: 1, a: 1}. -
Des index redondants peuvent aussi provenir de la combinaison d'un index unique avec d'autres champs. Par exemple, considérez les requêtes suivantes :
db.myCol.find({"a": 1, "b": 1})db.myCol.find({"a": 1, "c": 1})
Si le champ
apossède des valeurs uniques, la création d'un index composite incluant d'autres champs en plus dean'est pas utile pour ces requêtes. Créez uniquement un index sur{a: 1}.
Recommandations pour les index non équivalents
-
Évitez de créer un index composite pour certaines requêtes non équivalentes. Exemple :
db.myCol.find({"a": {$gte: 1} , "b": {$lte: 1}})Dans cette requête non équivalente sur plusieurs champs, seul le champ le plus à gauche peut être indexé efficacement. Créez uniquement un index sur le champ
a. -
Combinez les requêtes d'égalité et les requêtes non équivalentes. Exemple :
db.myCol.find({"a": {$gte: 1} , "b": 1})Dans ce cas, l'index optimal doit placer le champ d'égalité en premier. Créez l'index
{b: 1, a: 1}.
Recommandations pour les index de type $or
Les requêtes de type $or nécessitent la création d'un index pour chaque condition. Exemple :
db.myCol.find({$or: [{"a": 1, "b": 1}, {"c": 1, "d": 1}]})
Créez un index optimal pour chaque clause de la requête $or. Pour la requête {$or: [{"a": 1, "b": 1}, {"c": 1, "d": 1}]}, créez deux index séparés, {a: 1, b: 1} et {c: 1, d: 1}, plutôt qu'un seul index composite tel que {a: 1, b: 1, c: 1, d: 1}.
Recommandations pour les index de tri
-
Créez un seul index pour différentes requêtes de tri portant sur le même champ. Exemple :
db.myCol.find({}).sort({"a":1})db.myCol.find({}).sort({"a":-1})
Créez uniquement l'index
{a: 1}. -
Utilisez des requêtes de tri sur plusieurs champs. Exemple :
db.myCol.find({}).sort({"a":1, "b": -1})L'index
{a: 1, b: 1}n'est pas efficace pour cette requête. Créez l'index{a: 1, b: -1}. -
Combinez les requêtes d'égalité, de non-égalité et de tri. Exemple :
db.myCol.find({"a": 1, "b": 2, "c": {$gte: 1}}).sort({"d": 1, "e": -1})L'ordre des champs dans un index doit suivre la règle
equality->sort->non-equality. Par exemple, l'index est{a: 1, b: 1, d: 1, e: -1, c: 1}. -
Combinez les requêtes de type
$oret de tri. Exemple :db.myCol.find({$or: [{"a": 1, "b": 1}, {"c": 1, "d": 1}]}).sort({"e": -1})Cette requête peut être divisée en deux requêtes :
db.myCol.find({"a": 1, "b": 1}).sort({"e":-1})etdb.myCol.find({"c": 1, "d": 1}).sort({"e":-1}). En suivant la règle de combinaison des requêtes d'égalité et de tri, créez les index{a: 1, b: 1, e: -1}et{c: 1, d: 1, e: -1}.
Utilisation d'une projection pour limiter les champs retournés
Pour renvoyer uniquement des champs spécifiques d'un document, utilisez une projection afin d'améliorer les performances.
Par exemple, pour récupérer uniquement les champs timestamp, title, author et abstract de la collection posts, exécutez la requête suivante :
db.posts.find( {}, { timestamp : 1 , title : 1 , author : 1 , abstract : 1} ).sort( { timestamp : -1 } )
Utilisation de hint() pour forcer un index spécifique
Dans la plupart des cas, l'optimiseur de requêtes sélectionne l'index optimal. Toutefois, vous pouvez utiliser la méthode hint() pour forcer MongoDB à utiliser un index spécifique.
Par exemple, utilisez hint() pour des tests de performance ou pour des requêtes où vous devez sélectionner un champ inclus dans plusieurs index.
Utilisation des index partiels
Les index partiels réduisent la taille et la surcharge de performance des index en n'indexant que les documents correspondant à une expression de filtre.
Par exemple, une collection contient les champs a, b, c. Si vos conditions de requête incluent uniquement le champ a, créez un index uniquement sur le champ a.