Curso de MySQL
EXPLAIN en MySQL: analizar por qué una consulta va lenta
Por Víctor Peña · Publicado el

Hola, ¿cómo están? Continuando con el curso de MySQL, hoy veremos EXPLAIN: la herramienta que te dice qué está haciendo MySQL con tu consulta en lugar de que lo adivines.
Es lo que convierte la optimización en un trabajo de diagnóstico y no de intuición.
¡Empecemos!
Cómo se usa
Antepón EXPLAIN a cualquier consulta:
EXPLAIN SELECT * FROM citas WHERE estado = 'programada';
No ejecuta la consulta: te muestra el plan de ejecución, es decir, cómo piensa MySQL resolverla.
El resultado es una tabla con varias columnas. Vamos a las que importan.
La columna type: la más importante
Indica cómo accede MySQL a las filas. Ordenada de mejor a peor:
| Valor | Significa | Veredicto |
|---|---|---|
const |
Una sola fila por clave primaria | Óptimo |
eq_ref |
Una fila por cada fila de la otra tabla | Excelente |
ref |
Varias filas con un índice no único | Muy bien |
range |
Rango sobre un índice | Bien |
index |
Recorre el índice completo | Regular |
ALL |
Escanea toda la tabla | Problema |
Si ves ALL en una tabla grande, ahí está tu problema. Significa que MySQL está leyendo fila por fila porque no encontró ningún índice útil.
En tablas pequeñas ALL es normal y hasta preferible: leer 50 filas es más rápido que consultar un índice.
La columna key
Muestra qué índice está usando realmente.
EXPLAIN SELECT * FROM citas WHERE estado = 'programada';
Si key aparece como NULL, no está usando ninguno. Contrástalo con la columna possible_keys, que lista los que podría haber usado:
possible_keyscon valores ykeyenNULL→ MySQL descartó el índice, normalmente porque devolvería demasiadas filas.possible_keysenNULL→ no existe ningún índice aplicable. Ahí toca crear uno.
La columna rows
Estimación de cuántas filas va a examinar MySQL.
Es una estimación, no un número exacto, pero sirve para comparar: si tu tabla tiene 500.000 filas y rows dice 480.000, la consulta está leyendo prácticamente todo.
Lo que quieres ver es un número bajo en relación al tamaño de la tabla.
La columna Extra
Contiene avisos que conviene reconocer:
| Valor | Qué significa |
|---|---|
Using index |
Excelente. Responde solo con el índice, sin tocar la tabla |
Using where |
Filtra después de leer. Normal |
Using filesort |
Ordena en memoria o disco. El ORDER BY no usa índice |
Using temporary |
Crea una tabla temporal. Costoso |
Using index condition |
Filtra usando el índice. Bien |
Los dos que hay que vigilar son Using filesort y Using temporary. Aparecen sobre todo con ORDER BY y GROUP BY sin índice de apoyo, y en tablas grandes son la causa de que una consulta tarde segundos.
Y Using index es la mejor noticia posible: significa que el índice contiene todo lo que la consulta pide y MySQL no necesita leer la tabla. Se llama índice cubriente.
Un caso completo
Vamos a ver el antes y el después.
Antes, sin índice:
EXPLAIN SELECT fecha, costo FROM citas WHERE estado = 'programada';
type: ALL
possible_keys: NULL
key: NULL
rows: 500000
Extra: Using where
Traducción: lee las 500.000 filas y descarta las que no cumplen.
Creamos el índice:
CREATE INDEX idx_citas_estado ON citas(estado);
Después:
type: ref
possible_keys: idx_citas_estado
key: idx_citas_estado
rows: 1200
Extra: Using where
De 500.000 filas examinadas a 1.200. Eso es lo que buscas.
EXPLAIN ANALYZE: datos reales
Desde MySQL 8.0.18 existe una versión que sí ejecuta la consulta y reporta tiempos medidos:
EXPLAIN ANALYZE
SELECT c.fecha, p.nombre
FROM citas c
JOIN pacientes p ON c.paciente_id = p.id
WHERE c.estado = 'programada';
Devuelve el tiempo real de cada paso y cuántas filas se procesaron de verdad, no estimadas.
Es más fiable que EXPLAIN normal, porque las estimaciones pueden estar desactualizadas. Ojo con una cosa: al ejecutar realmente la consulta, no lo uses con UPDATE o DELETE en producción.
EXPLAIN con formato legible
EXPLAIN FORMAT=TREE
SELECT c.fecha, p.nombre
FROM citas c
JOIN pacientes p ON c.paciente_id = p.id;
Muestra el plan como un árbol, con el orden en que se ejecutan las operaciones. Es bastante más comprensible que la tabla de columnas cuando hay varios JOIN.
Los problemas más frecuentes que revela
1. Índice inutilizado por una función
EXPLAIN SELECT * FROM citas WHERE YEAR(fecha) = 2026;
-- type: ALL
EXPLAIN SELECT * FROM citas
WHERE fecha >= '2026-01-01' AND fecha < '2027-01-01';
-- type: range
Misma consulta lógica, plan completamente distinto.
2. Orden equivocado en un índice compuesto
Con el índice (doctor_id, fecha):
EXPLAIN SELECT * FROM citas WHERE fecha > '2026-04-01';
-- type: ALL ← no puede usarlo
Es la regla del extremo izquierdo que vimos en la lección de índices. EXPLAIN te lo confirma.
3. Ordenación sin índice
EXPLAIN SELECT * FROM citas ORDER BY costo DESC LIMIT 20;
-- Extra: Using filesort
Un índice sobre costo elimina el filesort.
4. JOIN sin índice en la clave foránea
EXPLAIN SELECT c.fecha, p.nombre
FROM citas c
JOIN pacientes p ON c.paciente_id = p.id;
Si la columna paciente_id no está indexada, verás ALL en esa tabla. Es la razón por la que declarar las claves foráneas ayuda: crean el índice automáticamente.
Un método de diagnóstico
Cuando una consulta va lenta:
- Ejecuta
EXPLAIN. - Busca
ALLen la columnatype. - Mira si
keyesNULL. - Compara
rowscon el tamaño real de la tabla. - Revisa
Extrabuscandofilesortotemporary. - Crea el índice que falte, o reescribe la consulta.
- Vuelve a ejecutar
EXPLAINy comprueba que cambió.
Ese último paso es el que cierra el círculo. Sin volver a medir, no sabes si tu cambio sirvió.
EXPLAIN en Workbench
Workbench tiene una vista gráfica: ejecuta la consulta y pulsa el icono de Explain junto al resultado. Muestra el plan como un diagrama con colores —verde para bien, rojo para escaneo completo— y el costo estimado de cada paso.
Es mucho más digerible que la tabla de texto cuando estás empezando.
Lo que EXPLAIN no te dice
Para tener expectativas realistas:
- No mide el tiempo real salvo que uses
EXPLAIN ANALYZE. - Las estimaciones pueden estar desactualizadas. Ejecuta
ANALYZE TABLEpara refrescarlas. - No detecta problemas de la aplicación, como el N+1: cada consulta suelta puede verse perfecta y aun así estar ejecutándose 500 veces.
Ejercicios
Con tu base de la clínica:
- Ejecuta
EXPLAINsobre una consulta filtrando porestadosin índice y anota eltype. - Crea el índice y repite. Compara.
- Prueba
WHERE YEAR(fecha) = 2026frente al rango equivalente. - Analiza una consulta con tres
JOINy revisa qué índice usa cada tabla.
Errores comunes
- Optimizar sin usar
EXPLAIN, a base de prueba y error. - Ignorar
Using filesortyUsing temporary. - Confiar en
rowscomo número exacto. - Analizar con datos de prueba. Con 50 filas todo parece rápido; el plan cambia con volumen real.
- No repetir el
EXPLAINdespués de crear el índice.
Para cerrar
EXPLAIN convierte «esta consulta va lenta» en «esta consulta escanea 480.000 filas porque no hay índice en la columna del WHERE». Es la diferencia entre diagnosticar y adivinar.
Lo esencial: busca ALL en type, NULL en key, y filesort o temporary en Extra. Con esos tres indicadores resuelves la mayoría de los casos.
En la siguiente lección veremos la búsqueda de texto completo.
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.
- Chatbots con Inteligencia Artificial
- Creación de agentes de IA
- Integración de IA en tus sistemas
- Desarrollo de software a medida
- Aplicaciones móviles iOS y Android
- Consultoría y asesoramiento técnico
Cotización sin costo · Respuesta directa por WhatsApp