sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Cuál es la diferencia entre LATERAL JOIN y una subconsulta en PostgreSQL?

Qué es un LATERAL unirse?

La función se introdujo con PostgreSQL 9.3. El manual:

Subconsultas que aparecen en FROM puede estar precedido por la palabra clave LATERAL . Esto les permite hacer referencia a las columnas proporcionadas por FROM anterior artículos. (Sin LATERAL , cada subconsulta se evalúa de forma independiente y, por lo tanto, no puede hacer una referencia cruzada con ningún otro FROM elemento.)

Funciones de tabla que aparecen en FROM también puede estar precedido por la palabra clave LATERAL , pero para funciones la palabra clave es opcional; Los argumentos de la función pueden contener referencias a columnas proporcionadas por FROM artículos en cualquier caso.

Allí se dan ejemplos de código básico.

Más como un correlacionado subconsulta

UN LATERAL join es más como una subconsulta correlacionada, no una subconsulta simple, en las expresiones a la derecha de un LATERAL join se evalúan una vez por cada fila que queda, al igual que un correlacionado subconsulta - mientras que una subconsulta simple (expresión de tabla) se evalúa una vez solamente. (Sin embargo, el planificador de consultas tiene formas de optimizar el rendimiento para cualquiera).
Respuesta relacionada con ejemplos de código para ambos, uno al lado del otro, resolviendo el mismo problema:

  • Optimizar la consulta GROUP BY para recuperar la fila más reciente por usuario

Para devolver más de una columna , un LATERAL join suele ser más simple, limpio y rápido.
Además, recuerde que el equivalente de una subconsulta correlacionada es LEFT JOIN LATERAL ... ON true :

  • Llamar a una función de devolución de conjuntos con un argumento de matriz varias veces

Cosas que una subconsulta no puede hacer

Hay son cosas que un LATERAL join puede hacerlo, pero una subconsulta (correlacionada) no puede (fácilmente). Una subconsulta correlacionada solo puede devolver un único valor, no varias columnas ni varias filas, con la excepción de las llamadas a funciones simples (que multiplican las filas de resultados si devuelven varias filas). Pero incluso ciertas funciones de devolución de conjuntos solo están permitidas en el FROM cláusula. Como unnest() con múltiples parámetros en Postgres 9.4 o posterior. El manual:

Esto solo está permitido en el FROM cláusula;

Entonces esto funciona, pero no se puede (fácilmente) reemplazar con una subconsulta:

CREATE TABLE tbl (a1 int[], a2 int[]);
SELECT * FROM tbl, unnest(a1, a2) u(elem1, elem2);  -- implicit LATERAL

La coma (, ) en el FROM cláusula es una notación abreviada para CROSS JOIN .
LATERAL se asume automáticamente para funciones de tabla.
Acerca del caso especial de UNNEST( array_expression [, ... ] ) :

  • ¿Cómo se declara que una función de devolución de conjunto solo se permita en la cláusula FROM?

Funciones de devolución de conjuntos en SELECT lista

También puede usar funciones de devolución de conjuntos como unnest() en el SELECT lista directamente. Esto solía exhibir un comportamiento sorprendente con más de una función de este tipo en el mismo SELECT lista hasta Postgres 9.6. Pero finalmente se ha saneado con Postgres 10 y ahora es una alternativa válida (incluso si no es SQL estándar). Ver:

  • ¿Cuál es el comportamiento esperado para varias funciones de devolución de conjuntos en la cláusula SELECT?

Basado en el ejemplo anterior:

SELECT *, unnest(a1) AS elem1, unnest(a2) AS elem2
FROM   tbl;

Comparación:

dbfiddle para pg 9.6 aquí
dbfiddle para la página 10 aquí

Aclarar información errónea

El manual:

Para el INNER y OUTER tipos de combinación, se debe especificar una condición de combinación, es decir, exactamente una de NATURAL , ON condición_de_unión ,o USING (join_column [,...]). Vea a continuación el significado.
Para CROSS JOIN , ninguna de estas cláusulas puede aparecer.

Entonces estas dos consultas son válidas (aunque no particularmente útiles):

SELECT *
FROM   tbl t
LEFT   JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t ON TRUE;

SELECT *
FROM   tbl t, LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;

Si bien este no lo es:

SELECT *
FROM   tbl t
LEFT   JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;

Por eso el código de ejemplo de Andomar es correcto (el CROSS JOIN no requiere una condición de unión) y is de Attila no lo era.