Curso de MySQL

Crear índices en MySQL: acelerar las consultas

Por Víctor Peña · Publicado el

Crear índices en MySQL

Hola, ¿cómo están? Continuando con el curso de MySQL, hoy veremos los índices. Es la herramienta que más impacto tiene sobre el rendimiento, y también la que más se usa mal.

¡Empecemos!

Qué es un índice

Un índice es una estructura auxiliar que MySQL mantiene para encontrar filas sin recorrer toda la tabla.

La analogía del índice de un libro es exacta: para buscar «normalización» en un manual de 800 páginas puedes leerlo entero, o ir al índice alfabético y saltar directo a la página 342.

Sin índice, MySQL hace un escaneo completo de tabla: lee todas las filas comprobando una por una. Con mil filas no se nota; con un millón, sí.

Crear un índice

CREATE INDEX idx_citas_estado ON citas(estado);

O al crear la tabla:

CREATE TABLE citas (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    fecha DATE NOT NULL,
    estado VARCHAR(20) NOT NULL,
    INDEX idx_citas_estado (estado),
    INDEX idx_citas_fecha (fecha)
);

Sobre el nombre: usa una convención como idx_tabla_columna. Cuando tengas veinte índices repartidos, agradecerás poder identificarlos de un vistazo.

Los que ya tienes sin saberlo

MySQL crea algunos índices automáticamente:

  • La clave primaria siempre está indexada.
  • Las columnas UNIQUE también.
  • Las claves foráneas llevan índice si declaraste la restricción.

Por eso las consultas por id son instantáneas desde el primer día.

Para ver los índices de una tabla:

SHOW INDEX FROM citas;

Qué columnas indexar

La regla general: las que aparecen en WHERE, en las condiciones ON de los JOIN y en ORDER BY.

-- Estas consultas se benefician de un índice en 'estado' y en 'fecha'
SELECT * FROM citas WHERE estado = 'programada';
SELECT * FROM citas WHERE fecha BETWEEN '2026-04-01' AND '2026-04-30';
SELECT * FROM citas ORDER BY fecha DESC LIMIT 20;

Pero hay un matiz importante que casi nadie menciona: el índice solo sirve si la columna es selectiva.

Una columna activo con valores 0 y 1 sobre un millón de filas indexa mal: si el 90 % está activo, el índice devuelve 900.000 filas y MySQL decide que le sale más barato leer la tabla entera. Y hace bien.

Los índices funcionan cuando filtran mucho. Una cédula, un correo, una fecha concreta: excelentes candidatos. Un campo de dos valores posibles: casi nunca.

Índices compuestos

Un índice puede cubrir varias columnas:

CREATE INDEX idx_citas_doctor_fecha ON citas(doctor_id, fecha);

Sirve para consultas que filtran por ambas:

SELECT * FROM citas WHERE doctor_id = 1 AND fecha >= '2026-04-01';

La regla del extremo izquierdo

Este es el concepto que más confusión genera, y el que hay que entender.

Un índice compuesto (doctor_id, fecha) se puede usar para:

WHERE doctor_id = 1                          -- sí
WHERE doctor_id = 1 AND fecha > '2026-04-01' -- sí

Pero no para:

WHERE fecha > '2026-04-01'                   -- no puede usarlo

La razón es la misma del listín telefónico: si está ordenado por apellido y luego por nombre, puedes buscar «todos los Torres» o «Torres, Ana». Pero para encontrar «todas las Anas» sin saber el apellido tienes que leerlo entero.

El orden de las columnas en un índice compuesto importa. Pon primero la que más filtre y la que uses en todas las consultas.

Un compuesto en vez de varios sueltos

Si tus consultas filtran siempre por las mismas dos columnas juntas, un índice compuesto es mejor que dos separados: MySQL normalmente usa un solo índice por tabla en cada consulta.

Índices únicos

Además de acelerar, garantizan que no haya duplicados:

CREATE UNIQUE INDEX idx_pacientes_cedula ON pacientes(cedula);

Es lo mismo que declarar la columna UNIQUE al crear la tabla. Sirve para cédulas, correos, códigos: cualquier dato que deba ser irrepetible.

Índices sobre parte de un texto

Para columnas de texto largas puedes indexar solo los primeros caracteres:

CREATE INDEX idx_pacientes_apellido ON pacientes(apellido(10));

Indexa los 10 primeros caracteres. Ocupa mucho menos y para búsquedas por prefijo funciona igual de bien.

El costo de los índices

Aquí está lo que casi ningún tutorial dice, y es fundamental:

Los índices no son gratis.

  • Ocupan espacio en disco. Un índice sobre una tabla grande puede pesar tanto como la tabla.
  • Ralentizan las escrituras. Cada INSERT, UPDATE y DELETE obliga a actualizar todos los índices de la tabla.

Una tabla con ocho índices puede tardar el doble en recibir una inserción que una con dos.

Por eso no se indexa «por si acaso». Cada índice debe justificarse con una consulta real que lo use.

Encontrar índices inútiles

SELECT
    TABLE_NAME,
    INDEX_NAME,
    COLUMN_NAME
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = 'clinica'
ORDER BY TABLE_NAME, INDEX_NAME;

Revisa esa lista de vez en cuando. En sistemas con años suelen sobrar índices que se crearon para una consulta que ya no existe.

Para eliminar uno:

DROP INDEX idx_citas_estado ON citas;

Cuándo el índice no se usa

Aunque exista, MySQL puede ignorarlo. Los casos más frecuentes:

Función sobre la columna:

WHERE YEAR(fecha) = 2026              -- no usa el índice
WHERE fecha >= '2026-01-01'
  AND fecha < '2027-01-01'            -- sí lo usa

Comodín al inicio en LIKE:

WHERE apellido LIKE '%rr%'    -- no
WHERE apellido LIKE 'To%'     -- sí

Comparación entre tipos distintos:

WHERE cedula = 1234567     -- si la columna es VARCHAR, puede no usarlo
WHERE cedula = '1234567'   -- correcto

Cuando devolvería demasiadas filas. Si el índice apunta a más o menos un tercio de la tabla, MySQL prefiere leerla completa.

Para saber si tu índice se está usando existe EXPLAIN, que veremos en dos lecciones.

Índices para nuestro sistema

Con las consultas que hemos escrito, estos tienen sentido:

-- Filtrado frecuente por estado y fecha
CREATE INDEX idx_citas_estado_fecha ON citas(estado, fecha);

-- Búsqueda de pacientes por apellido
CREATE INDEX idx_pacientes_apellido ON pacientes(apellido);

-- Las claves foráneas ya están indexadas por la restricción,
-- pero si no las hubieras declarado harían falta:
-- CREATE INDEX idx_citas_paciente ON citas(paciente_id);
-- CREATE INDEX idx_citas_doctor ON citas(doctor_id);

Fíjate en el orden del compuesto: estado primero porque aparece en más consultas, fecha después.

Un método para decidir

  1. Identifica las consultas lentas con el registro de consultas lentas.
  2. Mira su WHERE y su ORDER BY.
  3. Comprueba con EXPLAIN si hay escaneo completo.
  4. Crea el índice sobre esas columnas.
  5. Vuelve a medir.
  6. Revisa que no perjudicaste las escrituras.

Errores comunes

  • Indexar todas las columnas «por si acaso», castigando las escrituras.
  • Orden incorrecto en un índice compuesto.
  • Indexar columnas poco selectivas, como un booleano.
  • Duplicar índices: si tienes (a, b), un índice suelto sobre a sobra.
  • Aplicar funciones sobre la columna indexada.
  • No revisar si el índice realmente se usa.

Para cerrar

Los índices son la diferencia entre una consulta de 4 segundos y una de 4 milisegundos. Pero son un intercambio: aceleran la lectura y penalizan la escritura.

La regla que resume todo: indexa lo que consultas mucho y filtra bien; no indexes por costumbre.

En la siguiente lección veremos las subconsultas.

Saludos y éxitos.

Norvic Software

Desarrollamos el software que tu empresa necesita

Somos una fábrica de software en Bolivia. Construimos sistemas a medida y aplicaciones móviles, y llevamos Inteligencia Artificial a las empresas que ya tienen un sistema funcionando.

Solicitar cotizaciónVer todos los servicios

Cotización sin costo · Respuesta directa por WhatsApp