Pregunta 1¿Por qué un Index-Only Scan evita volver a la tabla base?
Index-Only Scan — un índice que se salta la tabla
Este artículo forma parte del Curso de SQL, con el que dominarás desde cero habilidades prácticas de SQL, desde lo básico hasta las consultas complejas y la optimización de SQL.
Pon cada columna que la consulta toca en el índice y el viaje de vuelta a la tabla base desaparece. Esto es un Index-Only Scan (índice cubriente). Aprenderás las condiciones que lo hacen funcionar, cómo se rompe en el momento en que falta una sola columna, y cómo plegar las columnas del filtro WHERE en un solo índice, todo verificado con EXPLAIN QUERY PLAN.
Salta la lectura de la tabla — el Index-Only Scan
Una búsqueda por índice normal encuentra la fila objetivo en el índice y luego vuelve a la tabla base para leer las otras columnas una fila a la vez.
Este viaje de vuelta se llama table lookup (el paso de extraer una fila de la tabla base vía el índice).
Cuando el conjunto de resultados es grande, esos viajes de ida y vuelta se acumulan y empiezan a costar tiempo real.
Si usas un índice que contiene cada columna que la consulta referencia, todos los valores están ahí mismo en el índice, y no hay necesidad de volver a la tabla en sí.
Este patrón, donde el índice solo entrega el resultado, se llama un Index-Only Scan (índice cubriente) (un índice que cubre cada columna que la consulta toca también se conoce como covering index).
-- Agregando region con un índice que contiene solo region
-- La columna referenciada (region) está completamente dentro del índice → sin viaje de vuelta a la tabla base
DROP INDEX IF EXISTS ix_demo;
CREATE INDEX ix_demo ON perf_sales(region);
EXPLAIN QUERY PLAN
SELECT region, COUNT(*)
FROM perf_sales
GROUP BY region;
Falta una sola columna y vuelves a la tabla base
Un Index-Only Scan solo ocurre cuando cada columna que la consulta toca — en SELECT, WHERE, GROUP BY, etcétera — está dentro del índice.
Falta una sola columna y la base de datos tiene que volver a la tabla base para leerla, y USING COVERING INDEX desaparece del plan.
Por ejemplo, con un índice sobre (emp_id, amount), escribir SELECT emp_id, SUM(amount), region añade region, que no está en el índice — así que la consulta vuelve a la tabla base para obtenerla.
-- Con un índice sobre (region, amount),
-- añadir product a las columnas referenciadas rompe el Index-Only Scan
DROP INDEX IF EXISTS ix_demo;
CREATE INDEX ix_demo ON perf_sales(region, amount);
-- region, SUM(amount) solo → totalmente cubierto por el índice
EXPLAIN QUERY PLAN
SELECT region, SUM(amount) FROM perf_sales GROUP BY region;
-- Añade product → no está en el índice, así que vuelve a la tabla base
EXPLAIN QUERY PLAN
SELECT region, SUM(amount), MAX(product) FROM perf_sales GROUP BY region;
Mantén el Index-Only Scan incluyendo también las columnas del filtro WHERE
SELECT no es el único lugar donde aparecen las columnas en tu consulta.
Las columnas del filtro WHERE también cuentan como columnas que la consulta toca, así que necesitan estar también en el índice — de lo contrario acabarás volviendo a la tabla base.
Pliégalas todas en un solo índice en el orden "columnas de filtro → columnas de salida / agregación", y tanto el filtrado como la recuperación de valores terminan dentro del mismo índice.
Por ejemplo, para filtrar con WHERE region = 'East' y calcular SUM(amount), pon la columna de filtro region primero y la columna de agregación amount segunda: (region, amount).
El índice acota a las filas objetivo por region y lee amount desde el mismo índice, así que no se necesita viaje de vuelta a la tabla base.
-- Pliega una columna de filtro (status) y una columna de agregación (amount) en un solo índice
DROP INDEX IF EXISTS ix_demo;
CREATE INDEX ix_demo ON perf_sales(status, amount);
EXPLAIN QUERY PLAN
SELECT SUM(amount)
FROM perf_sales
WHERE status = 'pending';
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2Dado un índice sobre (emp_id, amount), ¿qué consulta rompe el Index-Only Scan y vuelve a la tabla base?
Pregunta 3Para una consulta que filtra con WHERE region = 'East' y calcula SUM(amount), ¿qué índice soporta un Index-Only Scan?