Diagnostic et résolution des requêtes lentes dans MongoDB : un guide pratique
Maîtrisez l'art de diagnostiquer et de résoudre les requêtes lentes dans MongoDB. Ce guide pratique vous apprend à utiliser le profileur de base de données pour identifier les goulots d'étranglement et à exploiter la puissante méthode `explain()` pour analyser les plans d'exécution. Apprenez les stratégies d'indexation essentielles, y compris les règles ESR et la création d'index couvrants, pour optimiser les performances et garantir que votre base de données NoSQL fonctionne de manière optimale.
Diagnostiquer et Résoudre les Requêtes Lentes dans MongoDB : Un Guide Pratique
Les requêtes lentes dans MongoDB apparaissent généralement après la croissance de vos données, un changement dans votre modèle d'accès, ou lorsqu'un index ne correspond plus à la façon dont l'application lit les données. Vous pouvez remarquer des timeouts sur les points de terminaison API, des tableaux de bord qui se chargent lentement, ou une augmentation du CPU et des E/S disque même si le trafic semble normal.
Utilisez le profileur pour trouver l'opération lente, explain() pour voir comment MongoDB l'exécute, et des index ciblés pour réduire le travail que MongoDB doit effectuer.
Comprendre Pourquoi les Requêtes Deviennent Lentes
Avant de modifier les index, vérifiez les causes habituelles :
- Index manquants ou inefficaces : Sans un index utile, MongoDB peut effectuer un scan de collection et examiner chaque document.
- Complexité de la requête : Les opérations qui nécessitent des étapes d'agrégation, des tris importants, ou des recherches inter-collections peuvent être intrinsèquement lentes si elles ne sont pas optimisées.
- Volume de données : Même les requêtes indexées peuvent ralentir si l'ensemble de données est massif et que la requête doit encore traiter des millions de documents avant de filtrer.
- Contraintes matérielles : Une RAM insuffisante (entraînant un swap disque important) ou des E/S disque lentes peuvent dégrader les performances de toutes les opérations.
Étape 1 : Identifier les Requêtes Lentes à l'Aide du Profilage
La première étape de la résolution est l'identification. Le Profileur de Base de Données de MongoDB enregistre les temps d'exécution des opérations de base de données, vous permettant de cibler exactement les requêtes qui posent problème.
Activer et Configurer le Profileur
Le profileur fonctionne à différents niveaux. Le niveau 0 désactive le profilage. Le niveau 1 enregistre les opérations plus lentes que le seuil configuré. Le niveau 2 enregistre toutes les opérations.
Pour analyser les requêtes lentes, réglez généralement le niveau 1 avec un seuil tel que 50 millisecondes :
// Basculez vers la base de données que vous souhaitez profiler
use maBaseDeDonnees
// Capturez les opérations prenant plus de 50 millisecondes
db.setProfilingLevel(1, { slowms: 50 })
Examiner les Résultats du Profileur
Les opérations lentes enregistrées sont stockées dans la collection system.profile. Vous pouvez interroger cette collection pour voir les requêtes lentes récentes :
// Trouvez les opérations prenant plus de 50ms
db.system.profile.find({ ns: "maBaseDeDonnees.maCollection", millis: { $gt: 50 } }).sort({ ts: -1 }).limit(10).pretty()
Gardez le niveau 2 uniquement pour des investigations courtes. Il enregistre chaque opération et peut ajouter une surcharge sur une base de données de production occupée.
Étape 2 : Analyser l'Exécution des Requêtes avec explain()
Une fois que vous avez identifié une requête lente, utilisez explain() pour voir comment MongoDB la traite.
Utiliser explain('executionStats')
Le niveau de verbosité executionStats fournit la sortie la plus complète, y compris les temps d'exécution réels et l'utilisation des ressources.
Considérez cette requête lente ciblant la collection utilisateurs :
db.utilisateurs.find({ statut: "actif", ville: "Paris" }).sort({ dateInscription: -1 }).explain('executionStats')
Interpréter la Sortie
Les champs clés à inspecter dans la sortie de explain() sont :
| Champ | Description | Indicateur de Lenteur |
|---|---|---|
Étapes winningPlan |
Le plan d'exécution choisi par l'optimiseur. | Recherchez COLLSCAN, SORT bloquant, ou un index inattendu. |
executionStats.nReturned |
Le nombre de documents retournés par l'opération. | Un nombre élevé alors que peu de résultats sont attendus indique souvent un mauvais filtrage en amont. |
executionStats.totalKeysExamined |
Combien de clés d'index ont été vérifiées. | Devrait généralement être proche de nReturned si un index est utilisé efficacement. |
executionStats.totalDocsExamined |
Combien de documents ont été réellement récupérés depuis le disque/mémoire. | Un nombre élevé suggère que l'index n'était pas assez sélectif. |
executionStats.executionTimeMillis |
Le temps total pris pour l'exécution. | Comparez-le à la latence réelle. |
Le Drapeau Rouge : COLLSCAN
Si le plan gagnant contient COLLSCAN, MongoDB a scanné la collection. Cela signifie généralement que la requête a besoin d'un meilleur index, que le prédicat n'est pas sélectif, ou que la forme de la requête empêche l'utilisation de l'index.
Étape 3 : Mettre en Œuvre des Stratégies d'Indexation
Résoudre un COLLSCAN implique généralement de créer ou d'ajuster des index pour correspondre au modèle de requête.
Créer des Index Composés
Pour les requêtes impliquant plusieurs champs, comme des correspondances d'égalité, des filtres de plage, ou des tris, un index composé est souvent nécessaire. La directive ESR courante ordonne les champs de l'index composé en commençant par les prédicats d'égalité, puis les champs de tri, puis les prédicats de plage. C'est une directive, pas un remplacement pour les tests avec votre requête et vos données réelles.
Exemple de Scénario :
Requête : db.commandes.find({ statut: "EN_ATTENTE", clientId: 123 }).sort({ dateCommande: -1 })
Basé sur ESR, l'index devrait suivre cette structure :
- Prédicats d'égalité (
statut,clientId) - Prédicats de tri (
dateCommande)
Création de l'Index :
db.commandes.createIndex( { statut: 1, clientId: 1, dateCommande: -1 } )
Cet index permet à MongoDB de filtrer rapidement par statut et ID client, puis de récupérer efficacement les résultats déjà triés par dateCommande.
Gérer les Opérations de Tri
Si explain() montre une étape SORT bloquante après l'examen de nombreux documents, MongoDB n'a pas pu utiliser un index pour retourner le résultat dans l'ordre trié.
Les tris importants peuvent consommer de la mémoire et peuvent déborder sur le disque en fonction de la version du serveur et des options de commande. La meilleure solution est généralement un index qui prend en charge à la fois le filtre et le tri.
Assurez-vous que les champs utilisés dans la clause .sort() sont présents en tant qu'éléments finaux dans l'index composé approprié.
Étape 4 : Techniques d'Optimisation Avancées
Si l'indexation seule ne résout pas la lenteur, envisagez ces étapes avancées :
Optimisation des Projections
Utilisez la projection, le deuxième argument dans .find(), pour retourner uniquement les champs dont votre application a besoin. Cela réduit le transfert réseau et peut permettre une requête couverte lorsque les champs projetés sont dans l'index.
// Retourne uniquement les champs _id, nom et email
db.utilisateurs.find({ ville: "Lyon" }, { nom: 1, email: 1, _id: 1 })
Index Couvrants
Un index couvrant est l'objectif de performance ultime. Cela se produit lorsque tous les champs requis par la requête (dans le filtre, la projection et le tri) sont présents dans l'index lui-même. Lorsque cela se produit, MongoDB n'a jamais besoin de récupérer le document réel (COLLSCAN est évité, et totalDocsExamined sera 0 ou très bas).
Dans la sortie de explain(), un index couvrant se traduit par une étape montrant IXSCAN et totalDocsExamined étant 0.
Révision du Matériel et de la Configuration
Si totalKeysExamined et totalDocsExamined semblent raisonnables mais que la latence reste élevée, regardez au-delà de la forme de la requête. Vérifiez si le jeu de travail tient en mémoire, si la latence du disque est élevée, et si le serveur est sous pression d'écriture, de contention de verrouillage, ou de saturation du CPU.
À Retenir
Diagnostiquer les requêtes lentes dans MongoDB est une boucle : profilez la charge de travail, expliquez la requête lente, ajoutez ou ajustez l'index, puis mesurez à nouveau. Une bonne correction réduit les documents examinés, supprime les scans de collection ou les tris bloquants évitables, et améliore le chemin de requête réel que vos utilisateurs ressentent.
Liste de Contrôle Actionnable :
- Activez temporairement le profileur pour capturer les requêtes lentes (
slowms). - Exécutez la requête problématique en utilisant
explain('executionStats'). - Vérifiez la présence de
COLLSCANou d'untotalDocsExaminedélevé. - Créez ou modifiez des index composés basés sur la règle ESR pour couvrir les filtres et les tris.
- Vérifiez l'amélioration en ré-exécutant la commande
explain().