Comprendre les index MongoDB: Bonnes pratiques et erreurs fréquentes
Ces principes permettront de définir des index efficaces et adaptés à chaque collection, et d’améliorer grandement les performances sur les collections volumineuses.
La règle ESR (Equality, Sort, Range)
La recommandation de Mongodb est de respecter un ordre dans le choix des champs d’un index composé.
- Tout d’abord les Equality, c’est à dire les champs filtrés avec =, pour réduire rapidement la quantité de données à prendre en compte
db.cars.find( { manufacturer : ‘xxx’ } )
- Ensuite les Sort, c’est à dire un champ qu’on utilisera par exemple pour un ordre alphabétique ou un ordre numérique, ascendant ou descendant, pour éviter le tri en mémoire
db.cars.find( { manufacturer: ‘xxx’ } ).sort( { year: -1} )
- et enfin le Range, un champ associé à une comparaison $lt, $gt ou $in. Ce type de filtre est moins efficace et doit être positionné en dernier.
db.cars.find( { price: { $gte: 15000} } )
Selon ESR, l’index correspondant à ces filtres sera
{ manufacturer: 1, year: -1, price: 1 }
L’ordre dans l’index et l’ordre logique de la requête (equality → sort → range) doivent s’aligner pour que le query planner puisse en tirer le maximum.
Imaginons une collection de commandes (orders) et une requête qui cherche les commandes d’un client précis (customerId = equality), triées par date (orderDate = sort), pour un montant supérieur à 100€ (amount = range).
L’index optimal selon ESR est:
{ customerId: 1, orderDate: 1, amount: 1 }
Et la requête respectant le même principe:
db.orders.find({ customerId: « ABC123 », amount: { $gt: 100 } })
.sort({ orderDate: 1 })
Le nombre d'index
Un premier réflexe pourrait être de créer un index pour chaque champ utilisé dans les requêtes, mais cela peut rapidement devenir contre-productif. En effet, chaque index supplémentaire consomme de l’espace de stockage et va ralentir les opérations d’écriture, car MongoDB doit mettre à jour tous les index associés à un document chaque fois qu’il est modifié. Il est donc essentiel de trouver un équilibre entre les avantages des index pour les lectures et leur impact sur les écritures.
Le choix des champs à indexer
Les champs à prendre en compte en priorité sont ceux utilisés dans les requêtes les plus fréquentes et les plus critiques pour les performances.
Par exemple, sur une collection de produits, si une part importante des requêtes filtrent sur le “sku” associé au “supplier”, il serait judicieux de créer un index composé utilisant ces 2 champs.
En revanche, si un champ est rarement utilisé ou s’il a une faible sélectivité (c’est à dire qu’il a peu de valeurs uniques), l’indexer consommera des ressources inutilement sans apporter de bénéfices.
L'ordre des champs dans les index composés
Il est important d’examiner l’ordre des champs dans les index composés. Le premier champ d’un index composé doit être celui qui a une haute cardinalité, c’est-à-dire celui qui a le plus de valeurs uniques. Par exemple, si on crée un index composé sur les champs « country » et « city », et que la plupart des documents ont la même valeur pour « country » (par exemple, « USA »), alors cet index ne sera pas très efficace pour les requêtes qui filtrent par « city ». Dans ce cas, il serait préférable d’avoir un index composé avec « city » en premier. Cette règle de cardinalité s’applique sauf quand elle entre en conflit avec la règle ESR, qui reste prioritaire.
Dans un prochain article, nous verrons comment mesurer et ajuster l’efficacité des index avec explain()
Émilie BOEGLEN
Développeur web fullstack