J'ai une collection MongoDB pour les données météorologiques avec chaque document composé d'environ 50 champs de paramètres météorologiques différents. Exemple simple ci-dessous:
db.weather.find({},{ temp: 1})
Si je n'ai besoin que d'un seul champ de tous les documents, disons temp
, ma requête serait la suivante:
{ "wind":7, "swell":6, "temp":32, ... "50th_field":32 }
Donc, en interne, MongoDB doit-il récupérer l'intégralité du document pour un seul champ qui a été demandé (projeté)? Ne serait-ce pas une opération coûteuse?
J'ai essayé MongoDB Compass pour comparer les horaires, mais le temps requis était <1 ms, donc je n'ai pas pu comprendre.
3 Réponses :
Oui. Voici comment l'éviter:
find(Temp)
Courir:
db.coll.find({ temp:{ $ne:null }},{ temp:1, _id:0 })`
{}
déclenche collscan car l'algorithme tente de faire correspondre les champs de requête avec le projet
Avec {temp}, {temp, _id:0}
il dit: "Oh, j'ai seulement besoin de temp".
Il devrait également être judicieux de dire que {}, {temp, _id:0}
n'a besoin que d'index, mais ce n'est pas le cas.
Fondamentalement, l'utilisation de la projection avec des champs de limitation est toujours plus rapide que de récupérer le document complet, vous pouvez même utiliser l'index couvert pour éviter d'examiner les documents (pas d'E / S de disque) pour améliorer les performances de l'archive.
Vérifiez les totalDocsExamined
d' executionStats
de la démo ci-dessous, le totalDocsExamined
était de 0! mais vous devez supprimer le champ _id
dans la projection car il n'est pas inclus dans l'index.
Voir aussi: https://docs.mongodb.com/manual/core/query-optimization/#covered-query
> db.test.insertOne({name: 'TJT'}) { "acknowledged" : true, "insertedId" : ObjectId("5faa0c8469dffee69357dde3") } > db.test.createIndex({name: 1}) { "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 } db.test.explain('executionStats').find({name: 'TJT'}, {_id: 0, name: 1}) { "queryPlanner" : { "plannerVersion" : 1, "namespace" : "memo.test", "indexFilterSet" : false, "parsedQuery" : { "name" : { "$eq" : "TJT" } }, "winningPlan" : { "stage" : "PROJECTION", "transformBy" : { "_id" : 0, "name" : 1 }, "inputStage" : { "stage" : "IXSCAN", "keyPattern" : { "name" : 1 }, "indexName" : "name_1", "isMultiKey" : false, "multiKeyPaths" : { "name" : [ ] }, "isUnique" : false, "isSparse" : false, "isPartial" : false, "indexVersion" : 2, "direction" : "forward", "indexBounds" : { "name" : [ "[\"TJT\", \"TJT\"]" ] } } }, "rejectedPlans" : [ ] }, "executionStats" : { "executionSuccess" : true, "nReturned" : 1, "executionTimeMillis" : 0, "totalKeysExamined" : 1, "totalDocsExamined" : 0, "executionStages" : { "stage" : "PROJECTION", "nReturned" : 1, "executionTimeMillisEstimate" : 0, "works" : 2, "advanced" : 1, "needTime" : 0, "needYield" : 0, "saveState" : 0, "restoreState" : 0, "isEOF" : 1, "invalidates" : 0, "transformBy" : { "_id" : 0, "name" : 1 }, "inputStage" : { "stage" : "IXSCAN", "nReturned" : 1, "executionTimeMillisEstimate" : 0, "works" : 2, "advanced" : 1, "needTime" : 0, "needYield" : 0, "saveState" : 0, "restoreState" : 0, "isEOF" : 1, "invalidates" : 0, "keyPattern" : { "name" : 1 }, "indexName" : "name_1", "isMultiKey" : false, "multiKeyPaths" : { "name" : [ ] }, "isUnique" : false, "isSparse" : false, "isPartial" : false, "indexVersion" : 2, "direction" : "forward", "indexBounds" : { "name" : [ "[\"TJT\", \"TJT\"]" ] }, "keysExamined" : 1, "seeks" : 1, "dupsTested" : 0, "dupsDropped" : 0, "seenInvalidated" : 0 } } } }
MonogDB lira toutes les données, mais seul le champ temp
(et _id
) sera transmis sur votre réseau au client. Si votre document est plutôt volumineux, les performances globales devraient être meilleures lorsque vous projetez uniquement les champs dont vous avez besoin.