Les Requêtes Lentes dans MongoDB – Détection et Résolution
Introduction :
Les requêtes lentes sont l’un des problèmes les plus courants rencontrés dans MongoDB. Elles peuvent affecter les performances globales d’une application, entraîner une latence accrue pour les utilisateurs, et surcharger les ressources système. Dans cet article, nous examinerons les causes possibles des requêtes lentes dans MongoDB, les outils pour les détecter, les stratégies de résolution, et des exemples concrets pour chaque étape.
1. Pourquoi les requêtes sont-elles lentes dans MongoDB ?
Les performances des requêtes MongoDB dépendent de plusieurs facteurs. Voici les causes les plus fréquentes des requêtes lentes :
- Absence d’index approprié : Les scans complets de collections (collection scans) prennent du temps.
- Requêtes non optimisées : Une syntaxe ou des filtres mal conçus peuvent ralentir les résultats.
- Collections volumineuses : Une base de données contenant des millions de documents peut être lente sans stratégie d’indexation efficace.
- Problèmes de concurrence : Un grand nombre de requêtes simultanées peut provoquer des verrouillages ou une saturation des ressources.
- Manque de ressources système : Si le serveur manque de mémoire ou de CPU, les performances en souffrent.
2. Détection des requêtes lentes
a) Activer le Profiler MongoDB
MongoDB propose un outil intégré appelé Database Profiler qui enregistre des détails sur les opérations lentes.
Pour plus des détails sur le Database profiler voir cet article MongoDB profiler
Comment activer le Profiler :
// Activer le profiler pour toutes les opérations lentes (seuil de 100ms)
db.setProfilingLevel(1, { slowms: 100 });
Consulter les requêtes lentes : :
db.system.profile.find().sort({ ts: -1 }).limit(10);
b) Utiliser l’outil explain()
L’utilisation de la méthode explain()
permet de comprendre comment MongoDB exécute une requête.
db.orders.find({ status: « completed » }).explain(« executionStats »);
Résultat attendu :
- executionTimeMillis : Temps pris pour exécuter la requête.
- totalKeysExamined : Nombre de clés d’index analysées.
- totalDocsExamined : Nombre total de documents analysés.
Si totalDocsExamined
est bien supérieur au nombre de résultats retournés, cela indique l’absence d’un index ou un index inapproprié.
c) Analyser avec mongotop
L’outil en ligne de commande mongotop
montre le temps passé par MongoDB à lire ou écrire dans les collections. Cela aide à identifier les collections problématiques.
mongotop
d) Consulter les métriques dans MongoDB Atlas
Si vous utilisez MongoDB Atlas, accédez au tableau de bord « Performance Advisor ». Cet outil détecte automatiquement les requêtes lentes et suggère des optimisations (comme la création d’index).
3. Résolution des requêtes lentes
a) Créer et optimiser les index
Les index sont la première ligne de défense contre les requêtes lentes. MongoDB utilise les index pour rechercher efficacement les documents.
Exemple : Absence d’index
Supposons que la collection orders
contient 1 million de documents, et qu’une requête recherche tous les documents avec le statut « completed » :
db.orders.find({ status: « completed » });
Si aucun index n’existe sur le champ status
, MongoDB effectuera un scan complet de la collection (collection scan), ce qui est très coûteux.
Solution : Créer un index
db.orders.createIndex({ status: 1 });
Résultat :
Après la création de l’index, le même find()
devient beaucoup plus rapide, car MongoDB recherche directement dans l’index.
b) Réduire les données scannées
Les requêtes qui recherchent ou trient sans utiliser d’index appropriés peuvent analyser inutilement un grand nombre de documents.
Exemple : Problème avec un tri
db.orders.find().sort({ createdAt: -1 }).limit(10);
Si aucun index n’existe sur le champ createdAt
, MongoDB trie tous les documents de la collection avant d’appliquer la limite.
Solution : Ajouter un index pour le tri
db.orders.createIndex({ createdAt: -1 });
c) Limiter le nombre de documents retournés
Évitez de retourner des ensembles de données volumineux d’un seul coup. Utilisez la pagination avec les paramètres limit()
et skip()
.
db.orders.find({ status: « completed » }).limit(100).skip(200);
d) Réécrire les requêtes inefficaces
Problème : Utilisation des opérations $not
Les filtres comme $not
peuvent ralentir considérablement les requêtes car ils ne bénéficient pas des index.
Solution : Requêtes positives
Transformez les requêtes pour utiliser des index positifs. Par exemple :
// Moins efficace :
db.orders.find({ status: { $not: { $eq: « completed » } } });// Plus efficace :
db.orders.find({ status: { $in: [« pending », « cancelled »] } });
e) Optimiser les pipelines d’agrégation
Les pipelines d’agrégation complexes peuvent devenir lents si des étapes inutiles ou coûteuses sont utilisées.
Exemple : Pipeline non optimisé
db.orders.aggregate([
{ $match: { status: « completed » } },
{ $project: { year: { $year: « $createdAt » }, total: 1 } },
{ $group: { _id: « $year », totalSales: { $sum: « $total » } } }
]);
Optimisation : Ajouter un index sur les champs requis
Avant d’exécuter ce pipeline, assurez-vous que le champ status
est indexé :
db.orders.createIndex({ status: 1 });
f) Ajouter des projections
Les projections limitent les champs retournés par MongoDB, réduisant ainsi la quantité de données transférées.
Exemple :
db.orders.find({ status: « completed » }, { _id: 0, orderId: 1, total: 1 });
g) Augmenter les ressources matérielles
Si la base de données est optimisée mais que les requêtes restent lentes, il se peut que le serveur manque de CPU ou de mémoire. Dans ce cas :
- Augmentez la RAM pour stocker davantage de données dans le cache.
- Utilisez des SSD pour réduire la latence des lectures/écritures.
4. Exemple pratique : Résolution d’une requête lente
Problème :
Une requête pour trouver les commandes effectuées après une certaine date prend 5 secondes :
db.orders.find({ createdAt: { $gte: ISODate(« 2000-01-01 ») } });
Diagnostic :
- Profiler : La requête scanne 1 million de documents.
- Explain :
totalDocsExamined
: 1,000,000executionTimeMillis
: 3000ms
Résolution :
- Créez un index sur
createdAt
:
db.orders.createIndex({ createdAt: 1 });
2. Réexécutez la requête. L’analyse montre :
-
totalDocsExamined
: 10,000executionTimeMillis
: 50ms
Résultat :
La requête est maintenant 60 fois plus rapide.
En suivant ces étapes, vous pouvez efficacement détecter, analyser et résoudre les problèmes de requêtes lentes dans MongoDB. Une combinaison de bonnes pratiques de développement, d’indexation et d’optimisation des ressources garantit une base de données rapide et performante.