Pregunta 1¿Cuál es la mejor solución para una consulta que escribe la misma agregación con GROUP BY dos veces — una en la consulta principal y otra en una subconsulta del HAVING?
Eliminar trabajo repetido y optimizar subconsultas — ejemplos prácticos
Practica reescribir consultas para que la misma agregación no se calcule dos veces, las subconsultas correlacionadas colapsen en un solo GROUP BY y una tabla derivada se materialice una vez vía una CTE — comparando los planes de consulta antes y después.
Los datos que usamos en este artículo — perf_sales y employee
En el artículo anterior viste cómo reescribir IN / EXISTS y subconsultas correlacionadas.
Este artículo se construye sobre eso con reescrituras que evitan calcular dos veces la misma agregación (plegando agregaciones repetidas en un único resultado intermedio) y materializando tablas derivadas (construyendo una vez una subconsulta en una cláusula FROM y manteniéndola temporalmente) — practicado mediante ejemplos prácticos concretos.
No escribas la misma agregación dos veces — pliega la duplicación en un único resultado intermedio
Cuando quieres preguntar "¿el total de ventas de cada región está por encima del total medio entre todas las regiones?", escribir el total y la media como dos subconsultas separadas hace que perf_sales se escanee dos veces.
Si pliegas la misma agregación en una sola CTE y la calculas una vez, y luego reutilizas el resultado, solo escaneas una vez.
El patrón de reescritura es: detecta el caso donde "la misma agregación con GROUP BY aparece tanto en la consulta principal como en una subconsulta", eleva esa agregación a una sola CTE y haz que la consulta principal referencie la CTE en su lugar.
El resultado es idéntico, y el escaneo duplicado desaparece del plan.
-- Antes: el total y la "media entre regiones" se agregan por separado (perf_sales escaneada dos veces)
SELECT region, SUM(amount) AS total
FROM perf_sales
GROUP BY region
HAVING SUM(amount) > (
SELECT AVG(t) FROM (
SELECT SUM(amount) AS t FROM perf_sales GROUP BY region
)
);
-- Después: agrega por región una vez en una CTE
WITH region_total AS (
SELECT region, SUM(amount) AS total
FROM perf_sales
GROUP BY region
)
SELECT region, total
FROM region_total
WHERE total > (SELECT AVG(total) FROM region_total)
ORDER BY region;
Colapsa subconsultas correlacionadas en una agregación de una sola pasada
Cuando una condición como "¿el total de ventas de cada región está por encima del total máximo por empleado dentro de esa región?" se calcula como una subconsulta correlacionada por cada fila externa de región, la consulta interna se reevalúa una vez por cada región.
Esto también puede plegarse en una agregación de una sola vez con clave por región, y luego unirla con JOIN.
El patrón de reescritura es: toma una (SELECT aggregate ... WHERE child.key = parent.key) llamada por cada fila externa y conviértela en "construye una tabla agregada con GROUP BY key una vez, y luego únela con JOIN con la padre".
Las reevaluaciones por región se reemplazan por una sola agregación más un JOIN.
-- Antes: correlaciona por región para encontrar el "total máximo por empleado"
SELECT region,
(SELECT MAX(s) FROM (
SELECT SUM(amount) AS s FROM perf_sales p2
WHERE p2.region = p1.region GROUP BY emp_id
)) AS max_emp_total
FROM perf_sales p1
GROUP BY region;
-- Después: agrega una vez por (region, emp_id), luego toma el MAX por región
WITH emp_region AS (
SELECT region, emp_id, SUM(amount) AS s
FROM perf_sales
GROUP BY region, emp_id
)
SELECT region, MAX(s) AS max_emp_total
FROM emp_region
GROUP BY region
ORDER BY region;
Materializar tablas derivadas — construye la subconsulta del FROM una vez
Una tabla derivada — una subconsulta escrita en una cláusula FROM — referenciada en dos sitios a veces puede ser recalculada dos veces por el optimizador.
Si la construyes una vez y la mantienes temporalmente (la materializas), las referencias no la reconstruyen cada vez.
En SQLite, referenciar varias veces una CTE hace que EXPLAIN QUERY PLAN muestre una línea MATERIALIZE — confirmando que la CTE se materializa exactamente una vez.
En el ejercicio final de este artículo tomarás una tabla derivada pesada que agrega perf_sales por emp_id y se referencia dos veces, la convertirás en una CTE materializada una vez y confirmarás que MATERIALIZE aparece en el plan y que el escaneo ocurre solo una vez.
-- Antes: la misma tabla derivada referenciada en dos cláusulas FROM
SELECT a.emp_id, a.tot, b.avg_tot
FROM (SELECT emp_id, SUM(amount) AS tot FROM perf_sales GROUP BY emp_id) a
CROSS JOIN (
SELECT AVG(tot) AS avg_tot FROM (
SELECT emp_id, SUM(amount) AS tot FROM perf_sales GROUP BY emp_id
)
) b
ORDER BY a.emp_id;
-- Después: tabla derivada como una CTE referenciada dos veces (materializada una vez)
WITH emp_total AS (
SELECT emp_id, SUM(amount) AS tot
FROM perf_sales
GROUP BY emp_id
)
SELECT e.emp_id, e.tot, (SELECT AVG(tot) FROM emp_total) AS avg_tot
FROM emp_total e
ORDER BY e.emp_id;
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2¿Qué reescritura colapsa una correlación que llama a (SELECT aggregate ... WHERE child.key = parent.key) por cada fila externa del grupo?
Pregunta 3¿Qué indica MATERIALIZE en EXPLAIN QUERY PLAN?