web-dev-qa-db-fra.com

Comment la projection mongoDB affecte les performances?

De MongoDB documentation il est mentionné que:

Lorsque vous n'avez besoin que d'un sous-ensemble de champs de documents, vous pouvez obtenir de meilleures performances en renvoyant uniquement les champs dont vous avez besoin

Comment les champs de filtrage affectent les performances? Les performances sont-elles liées à la taille des données transmises sur le réseau? ou la taille des données qui seront conservées en mémoire? Comment exactement cette performance est-elle améliorée? Quelle est cette performance mentionnée dans la documentation?

J'ai des requêtes MongoDB lentes. Le renvoi d'un sous-ensemble affecte-t-il ma requête lente (j'ai un index composé sur le terrain)?

9
ALH

Par défaut, les requêtes renvoient tous les champs des documents correspondants. Si vous avez besoin de tous les champs, le retour de documents complets sera plus efficace que le fait que le serveur manipule l'ensemble de résultats avec des critères de projection.

Cependant, l'utilisation de la projection sur limiter les champs à renvoyer des résultats de la requête peut améliorer les performances en:

  • suppression des champs inutiles des résultats de la requête (économie de bande passante réseau)
  • limitation des champs de résultat pour obtenir une requête couverte (retour des résultats de requête indexés sans récupérer les documents complets)

Lors de l'utilisation de la projection pour supprimer les champs inutilisés, le serveur MongoDB devra récupérer chaque document complet en mémoire (s'il n'est pas déjà là) et filtrer les résultats pour revenir. Cette utilisation de la projection ne réduit pas l'utilisation de la mémoire ou l'ensemble de travail sur le serveur MongoDB, mais peut économiser une bande passante réseau importante pour les résultats des requêtes en fonction de votre modèle de données et des champs projetés.

Une requête couverte est un cas spécial où tous les champs demandés dans un résultat de requête sont inclus dans l'index utilisé, de sorte que le serveur n'a pas à extraire le document complet. Les requêtes couvertes peuvent améliorer les performances (en évitant la récupération de documents) et l'utilisation de la mémoire (si d'autres requêtes ne nécessitent pas la récupération du même document).

Exemples

À des fins de démonstration via le shell mongo, imaginez que vous avez un document qui ressemble à ceci:

db.data.insert({
    a: 'webscale',
    b: new Array(10*1024*1024).join('z')
})

Le champ b peut représenter une sélection de valeurs (ou dans ce cas une chaîne très longue).

Ensuite, créez un index sur {a:1} Qui est un champ couramment utilisé interrogé par votre cas d'utilisation:

db.data.createIndex({a:1})

Une simple findOne() sans critère de projection renvoie un résultat de requête d'environ 10 Mo:

> bsonsize(db.data.findOne({}))
10485805

L'ajout de la projection {a:1} Limitera la sortie au champ a et au document _id (Qui est inclus par défaut). Le serveur MongoDB manipule toujours un document de 10 Mo pour sélectionner deux champs, mais le résultat de la requête n'est plus que de 33 octets:

> bsonsize(db.data.findOne({}, {a:1}))
33

Cette requête n'est pas couverte car le document complet doit être récupéré pour découvrir la valeur _id. Le champ _id Est inclus par défaut dans les résultats de la requête car il s'agit de l'identifiant unique d'un document, mais _id Ne sera pas inclus dans un index secondaire sauf s'il est explicitement ajouté.

Les métriques totalDocsExamined et totalKeysExamined dans les résultats explain() montreront combien de documents et de clés d'index ont été examinés:

 > db.data.find(
     {a:'webscale'}, 
     {a:1}
 ).explain('executionStats').executionStats.totalDocsExamined
 > 1

Cette requête peut être améliorée à l'aide de la projection pour exclure le champ _id Et obtenir une requête couverte en utilisant uniquement l'index {a:1}. La requête couverte n'a plus besoin de récupérer un document de ~ 10 Mo en mémoire, elle sera donc efficace à la fois dans l'utilisation du réseau et de la mémoire:

 > db.data.find(
     {a:'webscale'},
     {a:1, _id:0}
 ).explain('executionStats').executionStats.totalDocsExamined
 0

 > bsonsize(db.data.findOne( {a:'webscale'},{a:1, _id:0}))
 21

J'ai des requêtes MongoDB lentes. Le renvoi d'un sous-ensemble affecte-t-il ma requête lente (j'ai un index composé sur le terrain)?

Ce n'est pas possible sans le contexte d'une requête spécifique, un exemple de document et la sortie d'explication complète. Cependant, vous pouvez exécuter des tests de performance dans votre propre environnement pour la même requête avec et sans projection pour comparer le résultat. Si votre projection ajoute une surcharge importante au temps d'exécution global des requêtes (traitement et transfert des résultats), cela peut être un indice fort que votre modèle de données pourrait être amélioré.

S'il n'est pas clair pourquoi une requête est lente, il serait préférable de poster une nouvelle question avec des détails spécifiques à étudier.

14
Stennie

Avec une projection, vous pouvez obtenir une situation où l'ensemble de résultats provient directement de l'index.

Si vous avez un indice composé {x:1, y:1, z:1} où aucun des x, y, z n'est _id, vous devez projeter {_id:0, x:1, y:1, z:1} parce que _id est toujours renvoyé dans le jeu de résultats (lorsqu'il n'est pas projeté) et le moteur doit lire les fichiers de données pour les obtenir. En effet, l'index n'a pas la valeur de _id, uniquement le pointeur sur le document où la valeur est stockée.

1
JJussi