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 pour limiter les champs à renvoyer des résultats de 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ée 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 de la requête 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 d'aller chercher des documents) et l'utilisation de la mémoire (si d'autres requêtes ne nécessitent pas d'aller chercher le même document).
Exemples
À des fins de démonstration via le mongo
shell, 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}
lequel se trouve un champ couramment utilisé interrogé par votre cas d'utilisation:
db.data.createIndex({a:1})
Un 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 _id
valeur. Le _id
champ 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
il ne sera pas inclus dans un index secondaire sauf s'il est explicitement ajouté.
Les mesures totalDocsExamined
et totalKeysExamined
dans les explain()
résultats 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 en utilisant la projection pour exclure le _id
champ et obtenir une requête couverte en utilisant uniquement l' {a:1}
index. 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.