El índice debería cubrir todas las partes de la consulta (parte de igualdad, parte de clasificación y parte de rango). Esto se debe a que en un típico find()
consulta, MongoDB solo usa un índice. Por ejemplo, generalmente no usa un índice para la parte de igualdad y otro índice para la parte de clasificación.
En general, la secuencia de campos en el índice debe seguir el patrón de igualdad -> ordenar -> rango .
Esto se describe en detalle en Optimización de índices compuestos de MongoDB .
Para su consulta, la parte de igualdad es tag:..., letterId:...
y la parte de clasificación es emailId:-1
. No hay una parte de rango en su consulta.
Usando este patrón, el índice compuesto que necesita es:
db.test.createIndex({tag:1, letterId:1, emailId:-1})
Intentemos confirmar cuánta mejora de rendimiento podemos obtener usando este índice.
Datos de prueba
Para confirmar la idoneidad del índice, inserté 1 millón de registros en una base de datos de prueba usando mgeneratejs , que es una herramienta para crear un documento aleatorio usando una plantilla.
Según su ejemplo, mgeneratejs
plantilla que estoy usando es:
$ cat template.json
{
"emailId": "$hash",
"email": "$email",
"letterId": "$hash",
"sendedFrom": "$email",
"resultMsg": "$word",
"owner": "$name",
"created": "$date",
"result": "$bool",
"tag": "$word",
"tryNum": {"$integer": {"min": 0, "max": 1e3}},
"clickHash": "$word",
"links": {"$array": {"of": "$url", "number": {"$integer": {"min": 1, "max": 5}}}}
}
e importó 1 millón de documentos aleatorios a MongoDB:
$ mgeneratejs template.json -n 1000000 | mongoimport -d test -c test
Prueba 1:índice no óptimo
Luego creé el índice que tiene e intenté encontrar un documento inexistente y reuní 10 ejecuciones de la consulta con la colección que contiene solo este índice:
> db.test.createIndex({emailId: 1, letterId: 1, result: 1, owner: 1, tag: 1, clickHash: 1})
> db.test.find({"tag" : "xyz", "letterId" : "abc"}).sort({emailId: -1}).limit(1)
Fetched 0 record(s) in 3069ms
Fetched 0 record(s) in 2924ms
Fetched 0 record(s) in 2923ms
Fetched 0 record(s) in 3013ms
Fetched 0 record(s) in 2917ms
Fetched 0 record(s) in 2961ms
Fetched 0 record(s) in 2882ms
Fetched 0 record(s) in 2870ms
Fetched 0 record(s) in 2969ms
Fetched 0 record(s) in 2863ms
por lo tanto, al usar ese índice, los tiempos de respuesta de la consulta no son excelentes, y la mayoría de las ejecuciones se acercan a los 3 segundos.
Prueba 2:igualdad -> ordenar -> índice de rango
Agregando la igualdad -> ordenar -> rango óptimo índice:
> db.test.createIndex({tag:1, letterId:1, emailId:-1})
> db.test.find({"tag" : "xyz", "letterId" : "abc"}).sort({emailId: -1}).limit(1)
Fetched 0 record(s) in 2ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 1ms
Fetched 0 record(s) in 3ms
Por el contrario, utilizando el índice óptimo, el rendimiento mejoró notablemente. Ninguna consulta devolvió en más de 3ms, con la gran mayoría de las veces regresa en 1ms.