Ir al contenido
wannacode

EXPLAIN: el plan de la consulta

En resumen: EXPLAIN muestra el plan de la consulta, es decir, cómo la ejecutará la base de datos: si lee toda la tabla o busca por un índice (en SQLite, EXPLAIN QUERY PLAN dice SCAN o SEARCH).

Problema

«El informe es lento»

Un compañero dice que el informe de las visitas de un cliente es lento. Podrías adivinar: quizá la tabla es grande, quizá la condición es complicada, quizá falta un índice. O puedes preguntarle a la base de datos cómo piensa ejecutarlo exactamente.

Toda base de datos hace primero un plan de consulta: por qué tabla empezar, si leer todo o buscar por un índice, si ordenar. Solo después lo ejecuta. El plan se puede ver.

La idea

EXPLAIN QUERY PLAN

En SQLite escribes EXPLAIN QUERY PLAN delante de la consulta. La consulta no se ejecuta. En lugar de un resultado obtienes el plan:

SQLbase de datos: tienda

La columna que importa es detail. id y parent ordenan los pasos en un árbol cuando hay varios, y notused no se usa. Aquí puedes ignorarlas. SCAN visits significa: leer toda la tabla fila por fila.

En este campo el índice sobre customer_id ya está creado:

SQLbase de datos: tienda

SEARCH significa una búsqueda por un índice. Los paréntesis dicen qué busca: customer_id=?, es decir, un valor de customer_id. SCAN o SEARCH es lo primero que miras en un plan.

Pruébalo

«Mis pedidos»

La página «Mis pedidos» busca los pedidos de un cliente por customer_id. Mira el plan en el campo y crea después un índice idx_orders_customer para que el plan de la misma consulta pase a ser SEARCH.

SQLbase de datos: tienda

La idea

Índice que cubre

Compara el plan de SELECT * de arriba con el plan de COUNT(*) con la misma condición:

SQLbase de datos: tienda

Aquí dice USING COVERING INDEX. El índice guarda el valor de customer_id y el número de fila. Para COUNT(*) eso basta: la base de datos cuenta las entradas del índice y no abre la tabla. Esto se llama índice que cubre (covering index).

SELECT * necesita también product_id y seen_at. No están en el índice, así que por cada entrada encontrada la base de datos va además a la tabla. El número de fila (id) está en cada entrada del índice, por eso SELECT id con la misma condición queda cubierto:

SQLbase de datos: tienda

Míralo

La ordenación oculta

La página muestra las visitas del cliente empezando por la más nueva. Ejecuta el plan:

SQLbase de datos: tienda

La segunda línea es USE TEMP B-TREE FOR ORDER BY. El índice ayudó a encontrar las filas, pero no están ordenadas por seen_at. Así que la base de datos las ordena ella misma, en una estructura temporal. Con 60 filas no es nada. Con 60 000 empiezas a notarlo. En la próxima lección haremos un índice que da las filas ya ordenadas.

Una búsqueda por clave primaria tiene su propia entrada en el plan:

SQLbase de datos: tienda

La idea

Cómo descubrir por qué es lento

Ejecuta el plan de la consulta lenta y busca:

  • SCAN de una tabla grande mientras la condición elige pocas filas. Falta un índice, o la condición no puede usarlo (esa es la última lección del módulo).
  • USE TEMP B-TREE. La base de datos ordena o agrupa por sí misma. Un índice en el orden correcto puede evitarlo.
  • SEARCH, pero sigue lento. La condición elige muchas filas, o el índice no cubre la consulta y se lee la tabla por cada fila.

El plan dice lo que va a pasar. Cuánto tarda, lo ves al ejecutar la consulta misma.

Más precisamente, para curiosos

En SQLite, EXPLAIN sin QUERY PLAN muestra el programa en el que SQLite convierte la consulta (instrucciones para su máquina virtual). Eso es para quienes trabajan en el propio SQLite.

En PostgreSQL, EXPLAIN muestra el plan con estimaciones: cuántas filas espera cada paso y cuánto «costará». EXPLAIN ANALYZE ejecuta de verdad la consulta y añade el tiempo real y el número real de filas de cada paso. Cuando la estimación y la realidad difieren mucho, ahí suele estar el origen de un plan lento. Allí una lectura completa se llama Seq Scan, una búsqueda por índice Index Scan y un índice que cubre Index Only Scan. Ojo: EXPLAIN ANALYZE sobre un UPDATE o un DELETE cambia los datos de verdad, así que ejecútalo dentro de una transacción y haz ROLLBACK después.

MySQL tiene EXPLAIN, y desde la versión 8.0.18 también EXPLAIN ANALYZE.

Ejercicio

Dos tareas

1. El informe de octubre cuenta las visitas a partir del 1 de octubre de 2026. Crea un índice idx_visits_seen para que el plan sea SEARCH.

Un índice que convierte el plan del informe de octubre en SEARCH:

SQLbase de datos: tienda

2. El cliente 4321 pide que se borren sus datos. Primero el programa solo necesita los números de sus visitas. El índice sobre customer_id ya está creado. Escribe la consulta de modo que la base de datos no lea la tabla.

Los números (id) de las visitas del cliente 4321, solo desde el índice:

SQLbase de datos: tienda

Test

Ponte a prueba

1. El plan dice SCAN visits. ¿Qué significa?
2. ¿Qué significa COVERING INDEX en un plan?
3. El plan tiene una línea USE TEMP B-TREE FOR ORDER BY. ¿Qué hace la base de datos?
4. ¿EXPLAIN QUERY PLAN SELECT … ejecuta la consulta?

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