Optimizar queries SQL no es un arte oscuro reservado para DBAs. Es una responsabilidad compartida, sobre todo cuando trabajamos con bases de datos PostgreSQL en aplicaciones que necesitan escalar o simplemente dejar de arrastrarse. Si estás lidiando con apps legacy llenas de consultas gigantes y poco documentadas, o si estás empezando desde cero con una arquitectura moderna, estos 10 puntos te pueden ahorrar dolores de cabeza y muchos EXPLAIN ANALYZE.
Crear un índice no es gratis. Sí, puede mejorar la lectura, pero penaliza escritura y ocupa espacio. Asegúrate de que realmente lo necesitas.
-- Útil si siempre filtras por "status"
CREATE INDEX idx_orders_status ON orders(status);
No indexes columnas con alta cardinalidad si tu filtro no las usa en WHERE o JOINs.
Antes de optimizar, entiende el plan de ejecución. EXPLAIN ANALYZE
te dice exactamente qué está haciendo PostgreSQL y cuánto tarda.
EXPLAIN ANALYZE
SELECT * FROM orders WHERE status = 'shipped';
¿Ves un "Seq Scan" en una tabla grande? Eso es una bandera roja.
Obvio, pero aún muy común. Seleccionar todas las columnas cuando solo necesitas dos es desperdiciar ancho de banda y RAM.
-- Malo
SELECT * FROM users;
-- Mejor
SELECT id, email FROM users;
Filtrar antes de hacer JOINs puede reducir drásticamente el número de registros intermedios.
-- Peor
SELECT * FROM orders o
JOIN users u ON o.user_id = u.id
WHERE u.country = 'AR';
-- Mejor
SELECT * FROM (
SELECT * FROM users WHERE country = 'AR'
) u
JOIN orders o ON o.user_id = u.id;
Usar funciones sobre columnas rompe el uso de índices. Evítalo o reescribe el query.
-- Evita esto
SELECT * FROM orders WHERE date_trunc('day', created_at) = '2025-08-01';
-- Mejor
SELECT * FROM orders
WHERE created_at >= '2025-08-01'
AND created_at < '2025-08-02';
Los CTEs (WITH
) son útiles para legibilidad, pero antes de PostgreSQL 12 eran tratados como barreras de optimización. Desde la versión 12, ya no lo son por defecto, pero sigue siendo importante medir el impacto.
WITH recent_orders AS (
SELECT * FROM orders WHERE created_at > NOW() - INTERVAL '30 days'
)
SELECT * FROM recent_orders WHERE status = 'pending';
Usa EXPLAIN
para asegurarte de que no te está costando rendimiento.
Cuando necesitas los primeros n resultados, asegúrate de tener un índice que soporte ese ORDER BY
.
-- Index que soporta esto:
CREATE INDEX idx_orders_created_at ON orders(created_at DESC);
-- Consulta eficiente:
SELECT * FROM orders ORDER BY created_at DESC LIMIT 10;
Si tienes una tabla logs
con millones de registros por año, el particionamiento puede hacer que ciertas consultas pasen de segundos a milisegundos.
CREATE TABLE logs_2025 (
CHECK (created_at >= '2025-01-01' AND created_at < '2026-01-01')
) INHERITS (logs);
Esto se puede automatizar con pg_partman
o scripts propios.
Si haces el mismo cálculo caro 100 veces por minuto, considera usar una tabla materializada.
CREATE MATERIALIZED VIEW top_users AS
SELECT user_id, COUNT(*) AS order_count
FROM orders
GROUP BY user_id
ORDER BY order_count DESC;
-- Luego:
REFRESH MATERIALIZED VIEW top_users;
Hacer casts implícitos fuerza scans innecesarios. PostgreSQL no puede usar el índice si estás comparando id::text
con una cadena.
-- Evita esto
SELECT * FROM users WHERE id::text = '123';
-- Mejor
SELECT * FROM users WHERE id = 123;
Característica | Apps Legacy | Apps Nuevas |
---|---|---|
Indexación | Mal planificada o inexistente | Pensada desde el diseño |
Uso de EXPLAIN | Casi nunca | Parte del workflow |
Tipos de datos | Genéricos (text everywhere) | Definidos con precisión |
Particionamiento | Ausente o hecho a mano | Automatizado o planeado |
Materialización | Evitada por complejidad | Usada para acelerar respuestas |
Código SQL | Incrustado y duplicado | Modular y probado |
Cultura de performance | Reactiva (cuando ya es lento) | Proactiva (tests, monitoreo) |
La diferencia entre una query que tarda 5 segundos y una que tarda 20ms muchas veces es solo cuestión de escribir mejor SQL.
No necesitas ser experto en PostgreSQL, pero sí necesitas medir y entender lo que escribes. A medida que crecen tus datos, también debe crecer tu responsabilidad sobre cómo los consultas.
¿Tienes alguna otra técnica que usás para mejorar tus queries? Comentala acá 👇
Me dedico a crear soluciones web eficientes y a compartir mi conocimiento con la comunidad de desarrolladores.