Per impostazione predefinita, le query restituiscono tutti i campi nei documenti corrispondenti. Se sono necessari tutti i campi, la restituzione di documenti completi sarà più efficiente rispetto al fatto che il server manipoli il set di risultati con criteri di proiezione.
Tuttavia, l'utilizzo della proiezione per limitare i campi da restituire dai risultati della query può migliorare le prestazioni:
- rimozione dei campi non necessari dai risultati della query (risparmio sulla larghezza di banda della rete)
- limitazione dei campi dei risultati per ottenere una query coperta (restituzione dei risultati della query indicizzata senza recupero di documenti completi)
Quando si utilizza la proiezione per rimuovere i campi non utilizzati, il server MongoDB dovrà recuperare tutti i documenti completi in memoria (se non è già presente) e filtrare i risultati per restituirli. Questo uso della proiezione non riduce l'utilizzo della memoria o il working set sul server MongoDB, ma può salvare una larghezza di banda di rete significativa per i risultati delle query in base al modello di dati e ai campi proiettati.
Una query coperta è un caso speciale in cui tutti i campi richiesti in un risultato della query sono inclusi nell'indice utilizzato, quindi il server non deve recuperare l'intero documento. Le query coperte possono migliorare le prestazioni (evitando il recupero di documenti) e l'utilizzo della memoria (se altre query non richiedono il recupero dello stesso documento).
Esempi
A scopo dimostrativo tramite la mongo
shell, immagina di avere un documento simile al seguente:
db.data.insert({
a: 'webscale',
b: new Array(10*1024*1024).join('z')
})
Il campo b
potrebbe rappresentare una selezione di valori (o in questo caso una stringa molto lunga).
Quindi, crea un indice su {a:1}
cui si trova un campo comunemente usato richiesto dal tuo caso d'uso:
db.data.createIndex({a:1})
Un semplice findOne()
senza criteri di proiezione restituisce un risultato della query di circa 10 MB:
> bsonsize(db.data.findOne({}))
10485805
L'aggiunta della proiezione {a:1}
limiterà l'output al campo a
e al documento _id
(incluso per impostazione predefinita). Il server MongoDB sta ancora manipolando un documento da 10 MB per selezionare due campi, ma il risultato della query ora è di soli 33 byte:
> bsonsize(db.data.findOne({}, {a:1}))
33
Questa query non è coperta perché è necessario recuperare l'intero documento per scoprire il _id
valore. Il _id
campo è incluso nei risultati della query per impostazione predefinita poiché è l'identificatore univoco di un documento, ma _id
non verrà incluso in un indice secondario se non viene aggiunto esplicitamente.
Le metriche totalDocsExamined
e totalKeysExamined
nei explain()
risultati mostreranno quanti documenti e chiavi di indice sono stati esaminati:
> db.data.find(
{a:'webscale'},
{a:1}
).explain('executionStats').executionStats.totalDocsExamined
> 1
Questa query può essere migliorata utilizzando la proiezione per escludere il _id
campo e ottenere una query coperta utilizzando solo l' {a:1}
indice. La query coperta non deve più recuperare un documento di ~ 10 MB in memoria, quindi sarà efficiente nell'uso della rete e della memoria:
> 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
Ho domande lente su MongoDB. La restituzione di un sottoinsieme influisce sulla mia query lenta (ho un indice composto sul campo)?
Non è possibile rispondere senza il contesto di una query specifica, un documento di esempio e l'output esplicativo completo. Tuttavia, è possibile eseguire alcuni benchmark nel proprio ambiente per la stessa query con e senza proiezione per confrontare il risultato. Se la tua proiezione sta aggiungendo un notevole sovraccarico al tempo complessivo di esecuzione della query (elaborazione e trasferimento dei risultati), questo potrebbe essere un forte suggerimento che il tuo modello di dati potrebbe essere migliorato.
Se non è chiaro il motivo per cui una query è lenta, sarebbe meglio pubblicare una nuova domanda con dettagli specifici per indagare.