Índices en MongoDB

Los índices en MongoDB se generan en forma de Árbol-B (B-Tree) Lo que quiere decir que los datos se guardan en forma de árbol, pero manteniendo nodos balanceados.

Ejemplo de Árbol-B

Así se incrementará la velocidad a la hora de buscar y también a la hora de devolver resultados ya ordenados. MongoDB es capaz de recorrer los índices en ambos sentidos, por lo que con solo un índice, podemos conseguir ordenación tanto ascendente como descendente.

Así para mejorar la eficiencia de los índices, es recomendable que tengan una cardinalidad alta. Es decir que, cuantos más valores únicos tenga el campo, más alta será la cardinalidad. Y más eficiente será el índice. Por ejemplo si tuviéramos un diccionario con miles de palabras que empiezan por la A y otras miles que empiezan por la B la búsqueda sería bastante tediosa.

Tipos de Índices en Mongo DB

A la hora de configurar un índice, tendremos las siguientes opciones.

Índices simples o de un solo campo en MongoDB

Estos índices se van a aplicar a un solo campo de nuestra colección.

Para declarar este tipo de índices debemos usar la siguiente sintaxis:

db.users.ensureIndex({ 'user_id': 1})

El número indica que queremos que el índice se ordene de forma ascendente.

Si quisiéramos un orden descendente, el parámetro será un -1

Índices compuestos en MongoDB

En este caso el índice se generará sobre varios campos.

db.users.ensureIndex({ 'nombre': 1, 'edad': -1})

Lo que definirá un índice ascendente para nombre y descendente para edad.

Así los datos se agruparán primero por el campo ‘nombre’ y el campo ‘edad’, quedaría algo así:

"Paco", 35
"Paco", 18
"María", 56
"María", 30
"María", 21
"Pedro", 19
"Pepe", 34
"Pepe", 27

Lo bueno de los índices compuestos, es que se pueden usar para consultar uno o varios campos, sin que sea necesario incluirlos todos.

En el ejemplo el índice se puede usar siempre que se hagan consultas sobre ‘nombre’ o sobre ‘nombre’ y ‘edad’. Lo que no podemos hacer es buscar sólo sobre el campo ‘edad’. Para ello deberíamos crear otro índice.

Si el índice compuesto tuviera 3 campos, se podría usar para consultar sobre el primer campo, sobre el primero y segundo, o sobre los tres campos.

Propiedades de Índices en MongoDB

Índices únicos en MongoDB

Los índices simples y múltiples, pueden estar obligados a contener valores únicos. Esto se consigue añadiendo el parámetro unique al crearlos.

db.users.ensureIndex({ 'user_id' : 1 }, {'unique' : true})

Así si intentamos insertar valores repetidos en algún campo que tenga un índice único, MongoDB nos va a devolver un error.

Índices Sparse en MongoDB

Los índices que hemos visto hasta ahora incluyen todos los documentos. También los documentos que no contengan el campo indexado. MongoDB no obliga a que usemos un esquema, así que no es obligatorio que los campos existan en el documento.

Para crear índices que sólo incluyan aquellos documentos cuyo campo indexado existe, usaremos la opción sparse.

db.users.ensureIndex({ 'nombre' : 1}, {'sparse': true})

Intersección de Índices en MongoDB

Antes de la versión 2.6 de MongoDB, cada consulta podía utilizar como máximo un índice. Esto era un problema en algunos casos. Por ejemplo imaginemos que necesitamos una consulta que ordena por ‘nombre’ de forma ascendente y ‘edad’ de forma descendente.

Si creamos un índice compuesto, como hemos visto anteriormente, tendríamos este problema solucionado.

db.users.ensureIndex({'nombre':1,'edad':-1});

¿Qué pasa si necesitamos también ejecutar consultas que devuelvan los resultados ordenador por ‘nombre’ ascendente y ‘edad’ también ascendente? Nos veríamos obligados a crear otro índice muy parecido:

db.users.ensureIndex({'nombre':1,'edad':1});

Para evitar estos problemas, aparecen los índices cruzados. De esta forma MongoDB puede usar varios índices en una consulta, para así mejorar el rendimiento de la misma. Si creamos dos índices, tendríamos el problema solucionado.

db.users.ensureIndex( { 'nombre' : 1 } )
db.users.ensureIndex( { 'edad' : -1 } )

Indexación de Subdocumentos en MongoDB

Supongamos que tenemos un documento con la siguiente estructura:

 { 
        "user_id": "DJK2312212",
        "info": 
        {
            "user_name": "Pedro",
            "age": 22
        }
    }

Si necesitamos crear un índice sobre el campo «user_name», podríamos hacerlo de la siguiente manera:

db.users.ensureIndex({ 'info.user_name': 1 });

También podríamos crear el índice sobre el nodo principal info, pero esto es algo que solo ayudaría en caso de que realizar consultas sobre el subdocumento completo y con los campos en el mismo orden.

Indexación de Arrays en MongoDB (Multikey)

También es posible indexar arrays en MongoDB aunque es algo que debemos hacer con cuidado teniendo en cuenta las limitaciones.

1ª Limitación: Sólo uno de los campos del índice puede ser un array.

Así si hubiéramos definido los siguientes dos índices:

db.users.ensureIndex({ 'categories': 1, 'tags': 1 })

Si intentamos insertar un documento con dos arrays, MongoDB nos devolverá un error:

db.users.insert({'categories':['game'.'book','movie'], 'tags':['horror','scifi','history']}) 
cannot index parallel arrays [categories][tags]

Es lógico puesto que por cada tupla del producto cartesiano habría que crear una entrada en el índice. En el caso de que los arrays fuesen grandes, sería una operación inmanejable.

2ª Limitación: Los elementos indexados del array, no tienen en cuenta el orden. Por tanto si realizamos consultas posicionales sobre el array, no se usará el índice.

Consultas completamente cubiertas por los índices en MongoDB

Aunque se tengan definidos varios índices, no todas las consultas van a ser igual de eficientes. Las consultas más rápidas serán las denominadas consultas totalmente cubiertas. Son aquellas consultas cuyos campos consultados y devueltos se encuentran incluidos en el índice.

Por ejemplo, suponiendo que tenemos el siguiente índice compuesto:

db.users.ensureIndex({ 'user_name' : 1, 'age' : 1})

Si realizamos una búsqueda que incluya en la consulta los campos user_name y/o age, y además, con los valores devueltos user_name y/o age, estaremos hablando de una consulta totalmente cubierta. MongoDB no tendrá que buscar en disco el documento completo, ya que los valores serán devueltos directamente desde el índice. Siempre que podamos debemos hacer consultas de este tipo.

Existen más tipos de índices como los índices de Texto, los Geospaciales o los Hashed…, para más información podéis consultar la página oficial de Mongo donde vienen explicados.

También te podría gustar...

Deja un comentario

Tu dirección de correo electrónico no será publicada.