Índices en MySQL

Un índice es una estructura de datos que acelera las búsquedas en una tabla. Sin índices, MySQL debe leer cada fila una por una. Con índices, puede saltar directamente a los datos que necesita.

¿Por qué importan los índices?

Imaginá que tenés una tabla con 1.000.000 de clientes y buscás uno por email. Sin índice, MySQL lee las 1.000.000 filas hasta encontrar la que coincide — eso se llama full table scan. Con un índice en la columna email, la búsqueda es casi instantánea.

-- Sin índice: MySQL lee TODAS las filas
SELECT * FROM clientes WHERE email = 'ana@mail.com';

-- Con índice en email: MySQL va directo al registro
-- (el índice funciona en segundo plano, la query es igual)
SELECT * FROM clientes WHERE email = 'ana@mail.com';
La PRIMARY KEY ya es un índice

Cuando definís una PRIMARY KEY, MySQL crea automáticamente un índice sobre esa columna. Por eso buscar por id siempre es rápido. También los campos UNIQUE generan índices automáticamente.

EXPLAIN — ver cómo MySQL ejecuta una query

EXPLAIN es la herramienta más importante para analizar el rendimiento. Te muestra el plan de ejecución: si usa un índice, cuántas filas examina, etc.

-- Ver cómo MySQL ejecuta esta query
EXPLAIN SELECT * FROM productos WHERE id_categoria = 1;

Las columnas más importantes del resultado:

ColumnaQué indicaQué querés ver
typeTipo de acceso a la tablaconst, ref, range — evitar ALL
keyÍndice que usaEl nombre del índice, no NULL
rowsFilas que estima examinarCuanto menor, mejor
ExtraInfo adicionalEvitar Using filesort, Using temporary
Probá el Ejemplo 1: EXPLAIN

Tipos de índices

INDEX — índice común

-- Crear un índice en una columna que se usa mucho en WHERE
CREATE INDEX idx_ciudad ON clientes (ciudad);

-- Ver los índices de una tabla
SHOW INDEX FROM clientes;

UNIQUE — valores únicos

-- Asegura que no haya dos filas con el mismo email
CREATE UNIQUE INDEX idx_email ON clientes (email);

Índice compuesto — varias columnas

-- Útil cuando filtrás por combinación de columnas
CREATE INDEX idx_ciudad_pais ON clientes (ciudad, pais);
El orden importa en índices compuestos

Un índice en (ciudad, pais) acelera búsquedas por ciudad sola o por ciudad + pais juntos. Pero NO acelera búsquedas solo por pais. Pensá en el índice como un directorio telefónico ordenado por apellido, luego nombre.

Eliminar un índice

DROP INDEX idx_ciudad ON clientes;
Probá el Ejemplo 2: SHOW INDEX

Cuándo usar (y no usar) índices

Columnas que se benefician de un índice

  • Columnas que aparecen frecuentemente en WHERE
  • Columnas usadas en JOIN (las claves foráneas)
  • Columnas en ORDER BY y GROUP BY en tablas grandes
  • Columnas que deben ser únicas (email, dni, etc.)

Cuándo NO agregar índices

  • Tablas pequeñas — el overhead del índice supera el beneficio
  • Columnas con muy pocos valores distintos (activo con solo 0 y 1)
  • Columnas que casi nunca se usan en WHERE o JOIN
  • Tablas con muchos INSERT/UPDATE — cada escritura actualiza todos los índices
Las foreign keys deberían tener índice

En MySQL las FOREIGN KEY crean un índice automáticamente en InnoDB. Pero es bueno saberlo: siempre que tenés una columna que usás en ON tabla.id = otra.id_tabla, esa columna debería estar indexada.

Probá el Ejemplo 3: EXPLAIN con y sin índice

Consultas que evitan el uso del índice

Hay patrones en las queries que impiden que MySQL use el índice aunque exista:

-- ❌ Función sobre la columna indexada — MySQL no puede usar el índice
SELECT * FROM clientes WHERE UPPER(ciudad) = 'CÓRDOBA';

-- ✅ Mejor: guardá los datos normalizados y comparalos igual
SELECT * FROM clientes WHERE ciudad = 'Córdoba';

-- ❌ LIKE con % al principio — escanea toda la tabla
SELECT * FROM clientes WHERE email LIKE '%@gmail.com';

-- ✅ LIKE con % solo al final — SÍ puede usar el índice
SELECT * FROM clientes WHERE email LIKE 'ana%';

-- ❌ Operación aritmética sobre la columna indexada
SELECT * FROM productos WHERE precio * 1.10 > 100;

-- ✅ Mejor: mover la operación al otro lado
SELECT * FROM productos WHERE precio > 100 / 1.10;
Probá el Ejemplo 4: EXPLAIN comparación

Buenas Prácticas

  • Usá EXPLAIN antes de optimizar — no asumas, medí; puede que la query ya sea rápida
  • Indexá las foreign keys — las columnas usadas en JOIN siempre deberían tener índice
  • No sobreindexes — cada índice extra ralentiza los INSERT, UPDATE y DELETE
  • Nombrá los índices descriptivamente — idx_clientes_ciudad es mejor que idx1
  • Revisá los índices existentes con SHOW INDEX — antes de crear uno nuevo, verificá que no exista ya