Ir al contenido
wannacode

Índices

En resumen: Un índice es una estructura aparte, ordenada, sobre una columna, que permite a la base de datos encontrar las filas que necesita sin leer toda la tabla.

Problema

Vistos recientemente

La tienda ha crecido. Cada vez que alguien abre la página de un producto, se guarda una fila en la tabla visits: qué cliente (customer_id), qué producto (product_id) y cuándo (seen_at). Esta tabla existe solo en este módulo: tiene 5 000 clientes y 300 000 visitas.

SQLbase de datos: tienda
SQLbase de datos: tienda

La página «Vistos recientemente» pide a la base de datos las visitas de un cliente. Ejecuta la consulta y mira el tiempo bajo el resultado:

SQLbase de datos: tienda

Unos milisegundos parecen poco. Pero la página la abren miles de personas, y la tabla crece cada día.

La idea

La base de datos lo lee todo

Las filas de la tabla no están ordenadas por cliente. Para encontrar las 60 visitas del cliente 1234, la base de datos lee las 300 000 filas y comprueba cada una.

Imagina que buscas la palabra «índice» en un libro de texto sin índice al final. Tendrías que pasar todas las páginas. Por eso un libro tiene al final un índice alfabético: las palabras están ordenadas, y junto a cada una están las páginas donde aparece.

Un índice de una tabla es lo mismo. Es una copia aparte, ordenada, de una columna, donde cada valor lleva una nota con el lugar de su fila. Como está ordenado, la base de datos busca partiendo por la mitad: mira en el medio, deduce en qué mitad está 1234, mira en el medio de esa mitad, y así sucesivamente. Para 300 000 valores bastan unos 19 pasos.

Aquí lo ves en una tabla pequeña con seis visitas, primero sin índice y luego con uno:

SELECT * FROM visits WHERE customer_id = 3;
CREATE INDEX idx_visits_customer ON visits(customer_id);
SELECT * FROM visits WHERE customer_id = 3;
Paso a paso, en palabras
  1. 6 visitas. Las filas no están ordenadas por customer_id: 5, 3, 8, 3, 1, 6.
  2. Sin índice, la base de datos hace un SCAN: lee fila por fila y compara customer_id con 3.
  3. Se leyeron 6 filas de 6, y coinciden 2: las filas con id 2 y 4.
  4. CREATE INDEX crea una copia ordenada de customer_id: 1, 3, 3, 5, 6, 8. Junto a cada valor anota de qué fila es.
  5. Con el índice es un SEARCH. En el medio está 5, más que 3: así que 3 está en la mitad de los valores menores, por encima de 5.
  6. En el medio de esa mitad está 3. Encima está 1, que es menor: este es el primer 3.
  7. Junto a 3 está la fila 2, junto al siguiente 3 la fila 4. Luego 5: terminado. De la tabla se leen solo 2 filas.

Un índice se crea con CREATE INDEX nombre ON tabla(columna). Ejecuta el campo dos veces y compara los tiempos:

SQLbase de datos: tienda

La primera vez se construye el índice, por eso es lenta. En la segunda el índice ya existe (IF NOT EXISTS se salta la creación, como en CREATE TABLE), y solo queda la búsqueda. Compárala con el tiempo de la consulta sin índice de la tarjeta anterior: la diferencia es de cientos de veces.

Más precisamente, para curiosos

Los índices de SQLite, PostgreSQL, MySQL y SQL Server son por defecto árboles B. No es una lista que se parte por la mitad, sino un árbol de páginas: cada página contiene cientos de valores ordenados y apunta al nivel siguiente. Por eso, incluso con millones de filas bastan tres o cuatro lecturas de página. La idea es la misma: ordenado, y cada paso descarta casi todo lo que no hace falta.

Pruébalo

Cuántas veces se ve un producto

La página de cada producto va a mostrar cuántas veces se ha visto. Crea un índice que acelere la búsqueda por producto y cuenta después las visitas del producto 7.

SQLbase de datos: tienda

La idea

Índices que ya tienes

La búsqueda por clave primaria es rápida sin CREATE INDEX:

SQLbase de datos: tienda

En SQLite una columna INTEGER PRIMARY KEY es el orden de la propia tabla: las filas se guardan por id. Así que no hace falta un índice aparte.

Para UNIQUE la base de datos crea un índice por su cuenta. Sin él, cada correo nuevo obligaría a leer todos los clientes para comprobar si ya existe. SQLite guarda la descripción de la base de datos en la tabla sqlite_master. Mira qué índices tiene la tienda:

SQLbase de datos: tienda

El primero es el de email en customers. El segundo es el de la clave primaria de order_items, que tiene dos columnas (order_id, product_id) y no es un INTEGER PRIMARY KEY.

Míralo

DROP INDEX

Un índice se elimina con DROP INDEX nombre. Los datos no cambian: solo desaparecen el índice y la búsqueda rápida. En este campo el índice sobre el cliente ya está creado. Ejecuta la consulta y mira el tiempo:

SQLbase de datos: tienda

El tiempo vuelve a ser el de antes, sin índice. Si ejecutas el campo una segunda vez, SQLite dirá que no existe ese índice. El botón «Base nueva» devuelve el estado inicial.

Ejercicio

Dos tareas

1. El informe «visitas por día» se ejecuta cada mañana. Crea un índice que lo acelere y cuenta con él las visitas del 1 de marzo de 2026.

Un índice para buscar por fecha, y el número de visitas del 2026-03-01:

SQLbase de datos: tienda

2. Se ha desactivado la página con el número de vistas de un producto. La base de datos tiene dos índices: idx_visits_customer e idx_visits_product. Elimina el que ya no hace falta.

Elimina el índice que nadie usa:

SQLbase de datos: tienda

Test

Ponte a prueba

1. La tabla no tiene índice sobre customer_id. ¿Qué hace la base de datos con WHERE customer_id = 1234?
2. ¿Por qué es rápida la búsqueda en un índice?
3. La tabla customers tiene email TEXT NOT NULL UNIQUE e id INTEGER PRIMARY KEY. ¿Qué búsqueda es rápida sin un índice nuevo?
4. ¿Qué pasa con los datos cuando ejecutas DROP INDEX?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·