Menú de navegación

Knowledge Programación Entornos de Programación
En este enlace puedes descargarte un fichero JSON comprimido formado por 10 millones de personas ficticias, generadas aleatoriamente a partir de la distribución de nombres y apellidos del INE. El fichero ocupa 159Mb comprimido y 1.1Gb al descomprimirlo.

Vamos a realizar algunas consultas con una colección que crearemos con estos datos, antes y después de crear índices y comprobaremos la diferencia.

1. Importación de los datos

Una vez descargado el fichero y descomprimirlo, deberás importar los datos en una colección que llamaremos "poblacion". Para ello usaremos el comando mongoimport. Aquí dividimos el comando en varias líneas pero tu puedes dejar todo en la misma línea:

 C:\~\bin>mongoimport.exe ^
  --db curso ^
  --collection poblacion ^
  --drop ^
  --file tmp\personas-10m.json
connected to: mongodb://localhost/
dropping: curso.poblacion
[........................] curso.poblacion      7.87MB/1.11GB (0.7%)
...
[########################] curso.poblacion      1.11GB/1.11GB (100.0%)
10000000 document(s) imported successfully. 0 document(s) failed to import.

La importación tardará alrededor de 10 minutos. Verificamos la carga contando el número de documentos:

 > db.poblacion.count()
10000000
2. Consulta sin índice

Ahora vamos a buscar todas las personas que se llamen PEDRO GARCIA FERNANDEZ. En vez de obtener los resultados vamos a concatenar explain() para obtener las estadísticas de la consulta:

 > db.poblacion.find( {
    nombre: "PEDRO",
    apellido1: "GARCIA",
    apellido2: "FERNANDEZ"
}).explain("executionStats")

La consulta la hemos hecho sin ningún tipo de índice. La salida resumida es la siguiente:

 {...
    "executionStats" : {
      "executionSuccess" : true,
      "nReturned" : 37,
      "executionTimeMillis" : 22395,
      "totalKeysExamined" : 0,
      "totalDocsExamined" : 10000000,
...}
Hemos obtenido 37 resultados en algo más de 22 segundos, para lo cual hemos tenido que recorrer los 10 millones de documentos de la colección (collection scan).
3. Creación de índices simples
Vamos a crear varios índices para mejorar esta consulta. Vamos a indexar los tres campos de la consulta:
 > db.poblacion.createIndex( { "nombre": 1 } )
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 2,
    "ok" : 1
}
> db.poblacion.createIndex( { "apellido1": 1 } )
...
> db.poblacion.createIndex( { "apellido2": 1 } )
...

La creación de los índices tardará unos 2 minutos por cada uno. Tras ello verificamos que se han creado con getIndexes():

 > db.poblacion.getIndexes()
[
    { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" },
    { "v" : 2, "key" : { "nombre" : 1 }, "name" : "nombre_1" },
    { "v" : 2, "key" : { "apellido1" : 1 }, "name" : "apellido1_1" },
    { "v" : 2, "key" : { "apellido2" : 1 }, "name" : "apellido2_1" }
]
4. Consulta con los índices simples
Repetimos nuestra consulta de prueba:
 > db.poblacion.find( {
    nombre: "PEDRO",
    apellido1: "GARCIA",
    apellido2: "FERNANDEZ"
} ).explain("executionStats")
{...
    "executionStats" : {
    "executionSuccess" : true,
    "nReturned" : 37,
    "executionTimeMillis" : 4529,
    "totalKeysExamined" : 50856,
    "totalDocsExamined" : 50856,
...}

Observamos que el tiempo de respuesta ha mejorado bastante, pasando a algo más de 4 segundos. Si la volvemos a ejecutar este tiempo bajará algo más, ya que la primera vez MongoDB realiza una competición entre los distintos planes de ejecución en función de los índices existentes, y las posteriores veces recuerda el plan ganador.

Al final la mejor opción ha sido la búsqueda del nombre por su índice, y tras ello recorre más de 50.000 documentos filtrando por los apellidos. No está mal, pero lo podemos hacer mejor.

5. Creación de un índice compuesto
Ahora creamos un nuevo índice compuesto por los tres campos de la consulta:
 > db.poblacion.createIndex( { "nombre": 1, "apellido1": 1, "apellido2": 1 } )
{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 4,
    "numIndexesAfter" : 5,
    "ok" : 1
}

La duración de la creación de este índice es similar a los de los anteriores.

6. Consulta con el índice compuesto
Con el nuevo índice compuesto creado volvemos a ejecutar nuestra consulta de prueba:
 > db.poblacion.find( {
    nombre: "PEDRO",
    apellido1: "GARCIA",
    apellido2: "FERNANDEZ"
} ).explain("executionStats")

{...
  "executionStats" : {
    "executionSuccess" : true,
    "nReturned" : 37,
    "executionTimeMillis" : 68,
    "totalKeysExamined" : 37,
    "totalDocsExamined" : 37
...}

La consulta ahora sí que es rápida. Solo 68 milisegundos para obtener los mismos resultados que antes. Ha mejorado más de 300 veces el rendimiento de la primera consulta sin índices. Como puedes observar los índices se deben adaptar a nuestras consultas. Solo se han recorrido las entradas del índice que corresponden a los documentos devueltos. A la hora de crear índices lo ideal es que los valores de nReturned y totalDocsExamined coincidan.

Como ejercicio prueba con distintas combinaciones de nombre y apellidos y comprueba los resultados. Puedes probar con tu propio nombre y apellidos para comprobar si se ha generado por probabilidad. Recuerda que la base de datos es ficticia.

Ejemplo de creación de índices
 

Esta píldora formativa está extraída del Curso online de Introducción a MongoDB.

¿Te gusta el contenido de esta píldora de conocimiento?

No pierdas tu oportunidad y ¡continúa aprendiendo!

ADR Formación

ADR Formación utiliza cookies propias y de terceros para fines analíticos anónimos, guardar las preferencias que selecciones y para el funcionamiento general de la página.

Puedes aceptar todas las cookies pulsando el botón "Aceptar" o configurarlas o rechazar su uso pulsando el botón "Configurar".

Puedes obtener más información y volver a configurar tus preferencias en cualquier momento en la Política de cookies