Accéder au contenu principal
MongoDB

Bonnes pratiques d’indexation MongoDB : astuces et conseils de performance

Découvrez comment créer des index MongoDB et des astuces pour en tirer les meilleures performances.
Nic Raboy's photo
Nic Raboy
Actualisé · 8 min lire

Explorez l'IA

ChatGPTClaudePerplexity

Créez votre compte gratuit

S'entraîner et cursus vos progrès.

Continuer Avec Google
En continuant, vous acceptez nos Conditions d'utilisation, notre Politique de confidentialité et le fait que vos données seront hébergées aux États-Unis.

Comme pour toute base de données, MongoDB incluse, les index sont essentiels au processus de développement. Sans eux, à mesure que votre base grandit, les performances chutent. Avec des index pertinents, la croissance des données s’accompagne d’un accès qui reste optimal.

Dans cet article, nous allons passer en revue les différents types d’index disponibles dans MongoDB, partager quelques conseils pour en tirer le meilleur parti, et expliquer comment vérifier que les index que vous créez sont réellement utilisés. Si vous débutez avec MongoDB, nous vous recommandons le cours Introduction to MongoDB.

Où les index MongoDB sont-ils cruciaux et pourquoi ?

Quand on parle d’index, on parle de performance. Les index font la différence entre parcourir chaque document d’une collection pour vérifier s’il correspond à la requête, et ne lire qu’un sous-ensemble ciblé de documents correspondants. Si la collection est petite, les performances seront correctes dans les deux cas. Mais avec 100 000 documents dont 100 seulement correspondent à la requête, sans index adapté il faudra du temps pour balayer 100 000 documents afin d’en extraire 100.

MongoDB propose de nombreux types d’index :

  • Champ unique : un index sur un champ précis du document. L’index par défaut sur le champ _id est un index à champ unique.
  • Composé : un index basé sur plusieurs champs d’un document, où l’ordre des champs utilisés dans la requête et dans l’index est important.
  • Multiclés : un index utilisé sur des champs de type tableau.
  • Générique (wildcard) : un index pour des champs dont le nom peut varier légèrement d’un document à l’autre. Ses performances sont inférieures à celles d’autres index.
  • Géospatial : un index qui accélère les requêtes géospatiales utilisant des coordonnées de latitude et longitude.
  • Haché : un index particulièrement adapté aux clés de partition (shard keys).

Pour en savoir plus sur les différents types d’index, consultez la documentation MongoDB.

La plupart du temps, vous utiliserez des index à champ unique, composés ou multiclés, mais au final, tout dépend de l’application, des requêtes et des données.

Les index sont importants pour toute interaction qui récupère des documents. Cela ne se limite pas aux opérations find ou findOne. Lors des mises à jour et suppressions, vous utilisez également un critère de correspondance qui sert à localiser les documents avant d’appliquer l’opération.

Les opérateurs find et findOne ne sont pas les seuls à bénéficier d’un index. Si vous utilisez l’opérateur $match en première étape d’un pipeline d’agrégation, un index accélère considérablement l’exécution.

Indexation MongoDB : conseils et astuces pour réussir

Créer des index au hasard peut être aussi inefficace que de ne pas en avoir. Voici quelques points à considérer pour bâtir une application bien plus efficiente.

Égalité, tri, intervalle (ESR) pour les index composés

La règle d’or pour un index composé consiste à déterminer l’usage de chaque champ dans la requête et à respecter la bonne pratique ESR.

Que signifie ESR ? Décomposons :

  • Égalité : des champs comparés à l’identique, pas de manière approximative. Par exemple, une correspondance exacte sur le nom d’une personne.
  • Tri : des champs utilisés pour trier en ordre croissant ou décroissant.
  • Intervalle : des champs filtrés par une plage de valeurs, et non par égalité. Par exemple, avec les opérateurs $lt ou $gt, on récupère des documents dans un intervalle, pas une valeur précise.

Pour mieux visualiser, regardez la requête suivante :

db.employee.find(
	{
		"department": "Developer Relations",
		"salary": {
			"$lt": 80000
		}
	}
).sort(
	{ 
		"name": 1 
	}
);

Cette requête applique une égalité sur department, un intervalle sur salary, puis trie par name.

En suivant ESR, l’index ressemblerait à ceci :

db.employee.createIndex({
	"department": 1,
	"name": 1,
	"salary": 1
});

On respecte ESR pour éviter les tris en mémoire et réduire l’espace de recherche, afin d’exécuter la requête plus efficacement.

Requêtes couvertes

L’indexation réduit déjà le volume de documents à analyser et améliore les performances. Pour aller plus loin, explorez les requêtes couvertes. Avec une requête couverte, tous les résultats proviennent directement de l’index, sans lecture des documents de la collection.

Quelques conditions peuvent toutefois limiter leur usage :

  • Les critères de filtrage et de tri doivent correspondre exactement à la définition de l’index.
  • Les champs projetés dans le résultat doivent aussi être inclus dans l’index.
  • En sharding, la clé de partition doit faire partie de l’index.

Concrètement, qu’est-ce que cela signifie ?

Prenons l’index suivant :

db.department.createIndex({
	"country": 1,
	"salary": 1
});

Ici, nous indexons les documents par country puis salary. Nous pouvons ensuite exécuter cette requête :

db.department.find(
	{
		"country": "US"
	},
	{
		"country": 1,
		"salary": 1
	}
);

Cette requête, avec projection, utilisera l’index, mais ne sera pas une requête couverte. Le champ _id est renvoyé par défaut dans MongoDB, et il n’est pas présent dans notre index. Il faut donc soit modifier l’index, soit ajuster la requête. En modifiant la requête :

db.department.find(
	{
		"country": "US"
	},
	{
		"country": 1,
		"salary": 1,
		"_id": 0
	}
);

Retenez que pour une requête couverte, l’index doit être valide et tous les champs demandés doivent y figurer. Sinon, vous ne faites qu’identifier des documents via l’index, sans tirer les résultats directement de l’index.

Vous pouvez vérifier si une requête est couverte en utilisant l’argument executionStats avec l’opérateur explain mentionné plus bas. Le champ totalDocsExamined vous l’indiquera : s’il vaut zéro, la requête est couverte.

Réduire ou éliminer les index superflus

Les index ont un coût en ressources serveur. Chacun doit être maintenu, ce qui consomme CPU, RAM et disque. Plus vous créez d’index, plus vous ajoutez de surcharge, pouvant entraîner des coûts plus élevés ou des performances dégradées si le serveur est sous-dimensionné. Cette dégradation touche aussi les écritures et suppressions, pas seulement les lectures, car MongoDB mobilise davantage de ressources.

Il est pertinent de créer des index uniquement pour les requêtes fréquentes. Une requête exécutée une fois par mois a-t-elle vraiment besoin d’un index ? Probablement pas. Celle qui s’exécute toutes les 10 secondes ? Absolument !

Découvrez d’autres bonnes pratiques d’indexation sur le blog MongoDB.

Votre index MongoDB fonctionne-t-il vraiment ?

Ce n’est pas parce que vous avez créé un index que votre requête l’utilise. Avec MongoDB, vous pouvez diagnostiquer quel index est utilisé pour une requête donnée.

Prenons l’index suivant :

db.people.createIndex({
	"name": 1,
	"is_active": 1
});

Ici, nous indexons les champs name et is_active. Exécutons maintenant la requête suivante :

db.people.find({
	"is_active": true
});

Cette requête s’exécutera avec ou sans index, et sera rapide si le jeu de données est petit. Pour vérifier si elle utilise notre index, modifions-la ainsi :

db.people.find({
	"is_active": true
}).explain();

Cette fois, nous appelons explain pour obtenir le plan d’exécution. Dans ce plan, on peut voir :

winningPlan: {
	isCached: false,
	stage: 'COLLSCAN',
	filter: { is_active: { '$eq': true } },
	direction: 'forward'
}

Pour cette requête, MongoDB a effectué un « COLLSCAN », ce qui signifie qu’aucun index n’a été utilisé, même si un des champs indexés figurait dans la requête. En la changeant ainsi :

db.people.find({
	"name": "Nic Raboy",
	"is_active": true
}).explain();

Le résultat d’explain change :

winningPlan: {
	isCached: false,
	stage: 'FETCH',
	inputStage: {
		stage: 'IXSCAN',
		keyPattern: { name: 1, is_active: 1 },
		indexName: 'name_1_is_active_1',
		isMultiKey: false,
		multiKeyPaths: { name: [], is_active: [] },
		isUnique: false,
		isSparse: false,
		isPartial: false,
		indexVersion: 2,
		direction: 'forward',
		indexBounds: {
			name: [ '["Nic Raboy", "Nic Raboy"]' ],
			is_active: [ '[true, true]' ]
		}
	}
},

Ici, le plan indique « IXSCAN » et précise le nom de l’index utilisé, name_1_is_active_1, nommé automatiquement à la création.

Pour une opération update, le principe est similaire, à ceci près que explain se place ailleurs.

Une opération update pourrait ressembler à ceci :

db.people.explain().update(
    {
        “name”: “Nic Raboy”,
        “Is_active”: true
    },
    {
        “$set”: { “is_active”: false }
    }
);

Remarquez que dans cet exemple, explain précède la fonction update.

Si l’index attendu est bien utilisé lors de la mise à jour, vous verrez « IXSCAN » ainsi que le nom de l’index. Plus d’informations sur les opérations d’update et l’usage des index.

Autre méthode pour consulter le plan d’exécution : utiliser runCommand sur la base. Moins lisible, mais très puissant :

db.runCommand({
    "explain": {
        "update": "people",
        "updates": [
            {
                "q": { 
                    "name": "Nic Raboy",
                    "is_active": true
                },
                "u": {
                    "$set": { "is_active": false }
                }
            }
        ]
    },
    "verbosity": "allPlansExecution"
});

Ce qui précède fournit les mêmes informations que l’usage d’explain avec update.

Si vous n’êtes pas à l’aise avec la création d’index, ou si vos requêtes sont plus lentes que prévu, examinez les détails d’exécution.

Conclusion

Vous venez de voir quelques bonnes pratiques d’indexation avec MongoDB. Sans couvrir tous les cas possibles, ces repères constituent une base solide pour offrir à vos utilisateurs la meilleure expérience possible avec vos données. 

En résumé :

  • Appliquez la règle égalité, tri, intervalle (ESR) autant que possible.
  • Lorsque c’est possible, visez une requête couverte.
  • Ne multipliez pas les index inutilement : identifiez les requêtes les plus utilisées et le volume de données qu’elles traitent.
  • Appuyez-vous sur l’opérateur explain pour tester vos index et leurs performances.

Cette liste n’est pas exhaustive. D’autres facteurs entrent en jeu, comme les niveaux de cardinalité.

Pour aller plus loin, consultez la documentation MongoDB. Si vous utilisez une offre payante sur MongoDB Atlas, pensez aux outils Performance Advisor intégrés pour recommander index et requêtes.

FAQ sur l’indexation MongoDB

Combien d’index dois-je créer dans une collection MongoDB ?

Ça dépend. Trouvez le bon équilibre pour votre usage : privilégiez l’indexation des requêtes exécutées fréquemment plutôt que ponctuellement.

J’ai créé quelques index, mais mes requêtes restent lentes. Pourquoi ?

Êtes-vous certain que vos requêtes utilisent réellement les index créés ? Utilisez l’opérateur explain ou les outils de recommandation de MongoDB Atlas pour diagnostiquer.

Pour la règle ESR, l’ordre des champs dans l’index doit-il être exactement égalité, puis tri, puis intervalle ?

MongoDB peut parfois utiliser un index même si l’ordre diffère, mais l’efficacité est maximale lorsque l’ordre des clés de l’index suit la séquence de la requête : d’abord les filtres par égalité, puis le tri, et enfin l’intervalle.

Quels sont les différents modes d’« explain » ?

Par défaut, explain() s’exécute en mode « queryPlanner ». Vous pouvez aussi utiliser les modes « executionStats » et « allPlansExecution ».


Nic Raboy's photo
Author
Nic Raboy

Nic Raboy est responsable des relations avec les développeurs chez MongoDB, où il dirige une équipe de développeurs Python, Java, C# et PHP qui créent un contenu génial pour aider les développeurs à réussir à inclure MongoDB dans leurs projets. Il a de l'expérience avec Golang et JavaScript et écrit souvent sur ses aventures de développement.

Sujets
MongoDB

Meilleurs cours DataCamp

Cours

Introduction à MongoDB en Python

3 h
24.4K
Apprenez à manipuler et analyser des données structurées de manière flexible avec MongoDB.
Voir les détailsCommencer Le Cours

Créez votre compte gratuit

S'entraîner et cursus vos progrès.

Continuer Avec Google
En continuant, vous acceptez nos Conditions d'utilisation, notre Politique de confidentialité et le fait que vos données seront hébergées aux États-Unis.
Voir plus
Contenus associés

blog

Architecture de l'entrepôt de données : Tendances, outils et techniques

Apprenez l'essentiel de l'architecture d'un entrepôt de données, des composants clés aux meilleures pratiques, pour construire un système de données évolutif et efficace !
Kurtis Pykes 's photo

Kurtis Pykes

15 min

Tutoriel

Données JSON Python : Un guide illustré d'exemples

Apprenez à utiliser JSON en Python, notamment la sérialisation, la désérialisation, le formatage, l'optimisation des performances, la gestion des API, ainsi que les limites et les alternatives de JSON.
Moez Ali's photo

Moez Ali

6 min

Tutoriel

Méthode index() de Python expliquée à l'aide d'exemples

Découvrez comment utiliser la fonction index() de Python pour trouver la position d'éléments dans des listes.
Sejal Jaiswal's photo

Sejal Jaiswal

6 min

Tutoriel

Power Pivot Excel : guide pas à pas

Apprenez à relier des tables, écrire des formules DAX et construire des rapports interactifs dans Excel.
Laiba Siddiqui's photo

Laiba Siddiqui

14 min

cursor ai code editor

Tutoriel

Cursor AI : Un guide avec 10 exemples pratiques

Apprenez à installer Cursor AI sur Windows, macOS et Linux, et découvrez comment l'utiliser à travers 10 cas d'utilisation différents.

Tutoriel

30 astuces Python pour un meilleur code, avec exemples

Nous avons sélectionné 30 astuces Python pour améliorer votre code et développer vos compétences en Python.
Kurtis Pykes 's photo

Kurtis Pykes

15 min

Voir plus