Il problema è che nessuno dei tuoi indici aiuta effettivamente con la query ordinata. Questo è il motivo dell'alto numero di oggetti scansionati e della presenza di SORT_KEY_GENERATOR
stage (ordinamento in memoria, limitato a 32 MB).
La query non ordinata, invece, può utilizzare sia la categoria { category: 1, _id: 1 }
o { category: 1, _id: 1, sticky: 1, lastPostAt: 1 }
indici. Nota che è perfettamente valido utilizzare uno dei due, poiché uno contiene il prefisso dell'altro. Vedi Prefissi per maggiori dettagli.
MongoDB find()
le query in genere utilizzano un solo indice, quindi un singolo indice composto dovrebbe soddisfare tutti i parametri della query. Ciò includerebbe entrambi i parametri di find()
e sort()
.
Un buon resoconto di come deve essere creato l'indice è disponibile in Ottimizzazione degli indici composti MongoDB. Prendiamo il punto principale dell'articolo, dove l'ordine composto dell'indice dovrebbe essere uguaglianza --> ordinamento --> intervallo :
La "forma" della tua query è:
db.collection.find({category:..., _id: {$gt:...}})
.sort({sticky:-1, lastPostAt:-1, _id:1})
.limit(25)
Lo vediamo:
category:...
è uguaglianzasticky:-1, lastPostAt:-1, _id:1
è ordina_id: {$gt:...}
è intervallo
Quindi l'indice composto di cui hai bisogno è:
{category:1, sticky:-1, lastPostAt:-1, _id:1}
Dove il piano vincente di explain()
l'output della tua query con l'indice sopra mostra:
"winningPlan": {
"stage": "LIMIT",
"limitAmount": 25,
"inputStage": {
"stage": "FETCH",
"inputStage": {
"stage": "IXSCAN",
"keyPattern": {
"category": 1,
"sticky": -1,
"lastPostAt": -1,
"_id": 1
},
"indexName": "category_1_sticky_-1_lastPostAt_-1__id_1",
"isMultiKey": false,
"multiKeyPaths": {
"category": [ ],
"sticky": [ ],
"lastPostAt": [ ],
"_id": [ ]
},
"isUnique": false,
"isSparse": false,
"isPartial": false,
"indexVersion": 2,
"direction": "forward",
"indexBounds": {
"category": [
"[ObjectId('5a779b31f4fa724121265142'), ObjectId('5a779b31f4fa724121265142')]"
],
"sticky": [
"[MaxKey, MinKey]"
],
"lastPostAt": [
"[MaxKey, MinKey]"
],
"_id": [
"(ObjectId('5a779b5cf4fa724121269be8'), ObjectId('ffffffffffffffffffffffff')]"
]
}
}
}
}
Nota che il piano vincente non contiene un SORT_KEY_GENERATOR
fase. Ciò significa che l'indice può essere utilizzato completamente per rispondere alla query ordinata.