Subconsultas y EXISTS
EXISTS comprueba la presencia sin devolver filas duplicadas de un hijo de uno a muchos. IN funciona para conjuntos estáticos pequeños; EXISTS escala mejor para semi-joins correlacionados.
Receta
SELECT c.id, c.email
FROM app.customers c
WHERE EXISTS (
SELECT 1 FROM app.orders o
WHERE o.customer_id = c.id AND o.total > 1000
);
SELECT id FROM app.customers
WHERE id IN (SELECT customer_id FROM app.orders WHERE total > 1000);Cuándo usar esto: Este patrón aparece en SQL de aplicaciones o informes que mantienes.
Ejemplo de trabajo
SELECT c.email
FROM app.customers c
WHERE NOT EXISTS (
SELECT 1 FROM app.orders o WHERE o.customer_id = c.id
);Lo que esto demuestra:
- EXISTS se detiene en la primera coincidencia.
- NOT EXISTS encuentra clientes sin pedidos.
- Equivalente a IN cuando la clave hija es única por filtro padre.
Profundización
Cómo funciona
- PostgreSQL analiza el SQL en un árbol de consulta.
- El planificador estima los costos utilizando estadísticas.
- El ejecutor devuelve filas al protocolo del cliente.
Notas
- Prefiere SQL legible; los optimizadores reescriben internamente.
- Prueba con recuentos de filas similares a los de producción.
Trampas
- IN con NULL en subconsulta - Desconocido envenena el resultado a desconocido. Solución: Usa NOT EXISTS o fuerza claves NOT NULL.
- Listas IN grandes - Miles de literales se analizan lentamente. Solución: Usa join de tabla temporal o = ANY(array).
- Costo de bucle anidado correlacionado - EXISTS por cada fila externa sin índice. Solución: Indexa las columnas de join del hijo.
Alternativas
| Alternativa | Usar cuando | No usar cuando |
|---|---|---|
| Constructor de consultas ORM | El equipo se estandariza en una pila | SQL complejo se vuelve opaco |
| Vista materializada | Repetir agregaciones costosas | Necesita estrategia de actualización |
| Réplica de almacén de datos | Escaneos pesados de BI | No para latencia OLTP |
Preguntas frecuentes
¿Debo formatear SQL en cadenas de aplicación?
Usa cadenas de plantilla multilínea o archivos SQL; haz lint en CI.
¿Cuándo es DISTINCT suficiente?
Cuando necesitas filas únicas sin agregados.
¿ORDER BY perjudica a los índices?
El ordenamiento puede usar el orden del índice si la consulta coincide con las columnas del índice.
Relacionado
- Tipos de JOIN - cuándo join reemplaza a exists
- Joins LATERAL - subconsultas por fila
Versiones de Stack: Esta página fue escrita para PostgreSQL 18.4 (estable 18, mantenimiento 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x y PostGIS 3.5+.