Puede pensar en el índice de campo único de MongoDB como una matriz, con punteros a ubicaciones de documentos. Por ejemplo, si tiene una colección con (tenga en cuenta que la secuencia está desordenada deliberadamente):
[collection]
1: {a:3, b:2}
2: {a:1, b:2}
3: {a:2, b:1}
4: {a:1, b:1}
5: {a:2, b:2}
Índice de campo único
Ahora si lo haces:
db.collection.createIndex({a:1})
El índice se parece aproximadamente a:
[index a:1]
1: {a:1} --> 2, 4
2: {a:2} --> 3, 5
3: {a:3} --> 1
Tenga en cuenta tres cosas importantes:
- Está ordenado por
a
ascendente - Cada entrada apunta a la ubicación donde residen los documentos relevantes
- El índice solo registra los valores de
a
campo. Elb
el campo no existe en absoluto en el índice
Así que si haces una consulta como:
db.collection.find().sort({a:1})
Todo lo que tiene que hacer es recorrer el índice de arriba a abajo, obteniendo y generando el documento al que apuntan las entradas. Tenga en cuenta que también puede recorrer el índice desde la parte inferior, por ejemplo:
db.collection.find().sort({a:-1})
y la única diferencia es que recorres el índice al revés.
Porque b
no está en el índice en absoluto, no puede usar el índice al consultar algo sobre b
.
Índice compuesto
En un índice compuesto, por ejemplo:
db.collection.createIndex({a:1, b:1})
Significa que desea ordenar por a
primero, luego ordenar por b
. El índice se vería así:
[index a:1, b:1]
1: {a:1, b:1} --> 4
2: {a:1, b:2} --> 2
3: {a:2, b:1} --> 3
4: {a:2, b:2} --> 5
5: {a:3, b:2} --> 1
Tenga en cuenta que:
- El índice se ordena de
a
- Dentro de cada
a
tienes unb
ordenado - Tiene 5 entradas de índice frente a solo tres en el ejemplo anterior de un solo campo
Usando este índice, puede hacer una consulta como:
db.collection.find({a:2}).sort({b:1})
Puede encontrar fácilmente donde a:2
luego camine el índice hacia adelante. Dado ese índice, no se puede :
db.collection.find().sort({b:1})
db.collection.find({b:1})
En ambas consultas no puede encontrar fácilmente b
ya que está repartido por todo el índice (es decir, no en entradas contiguas). Sin embargo, puedes hacer:
db.collection.find({a:2}).sort({b:-1})
ya que esencialmente puedes encontrar dónde está el a:2
son, y caminan por el b
entradas hacia atrás.
Editar :aclaración de la pregunta de @marcospgp en el comentario:
La posibilidad de utilizar el índice {a:1, b:1}
para satisfacer find({a:2}).sort({b:-1})
en realidad tiene sentido si lo ve desde el punto de vista de una tabla ordenada. Por ejemplo, el índice {a:1, b:1}
se puede considerar como:
a | b
--|--
1 | 1
1 | 2
2 | 1
2 | 2
2 | 3
3 | 1
3 | 2
buscar({a:2}).ordenar({b:1})
El índice {a:1, b:1}
significa sort by a, then within each a, sort the b values
. Si luego haces find({a:2}).sort({b:1})
, el índice sabe dónde están todos los a=2
son. Dentro de este bloque de a=2
, el b
se ordenaría en orden ascendente (según la especificación del índice), de modo que la consulta find({a:2}).sort({b:1})
puede ser satisfecho por:
a | b
--|--
1 | 1
1 | 2
2 | 1 <-- walk this block forward to satisfy
2 | 2 <-- find({a:2}).sort({b:1})
2 | 3 <--
3 | 1
3 | 2
buscar({a:2}).ordenar({b:-1})
Dado que el índice se puede caminar hacia adelante o hacia atrás, se siguió un procedimiento similar, con un pequeño giro al final:
a | b
--|--
1 | 1
1 | 2
2 | 1 <-- walk this block backward to satisfy
2 | 2 <-- find({a:2}).sort({b:-1})
2 | 3 <--
3 | 1
3 | 2
El hecho de que el índice se pueda recorrer hacia adelante o hacia atrás es el punto clave que permite la consulta find({a:2}).sort({b:-1})
para poder usar el índice {a:1, b:1}
.
Explicación del planificador de consultas
Puede ver lo que planea el planificador de consultas usando db.collection.explain().find(....)
. Básicamente, si ves un stage
de COLLSCAN
, no se usó ni se puede usar ningún índice para la consulta. Ver explicar resultados
para obtener detalles sobre la salida del comando.