PostgreSQL에서 LATERAL과 하위 쿼리의 차이점은 무엇입니까?


146

Postgres는 LATERAL조인 을 수행 할 수있는 기능을 제공 했으므로 현재 전체 쿼리에 4 분 이상 걸리는 비효율적 인 하위 쿼리가 많은 팀에 대해 복잡한 데이터 덤프를 수행하고 있기 때문에 자세히 읽었습니다.

나는 이해가 LATERAL나를 도울 수 있습니다 조인하지만, 심지어 같은 기사를 읽은 후 이 하나의 힙 애널리틱스를, 나는 여전히 매우 따르지 않습니다.

LATERAL조인 의 사용 사례는 무엇입니까 ? LATERAL조인과 하위 쿼리 의 차이점은 무엇입니까 ?


2
blog.heapanalytics.com/...explainextended.com/2009/07/16/inner-join-vs-cross-apply는 (SQL 서버의는 apply와 동일한 lateralSQL 표준에서)
a_horse_with_no_name

답변:


163

상관 된 것처럼 하위 쿼리

A는 LATERAL(포스트 그레스 9.3 이상)이 더 같은 조인 상관 하위 쿼리 가 아닌 일반 서브 쿼리. 마찬가지로 Andomar 지적 A는 오른쪽에, 함수 또는 하위 쿼리를 LATERAL단지처럼 - 그것의 왼쪽 각 행에 대해 한 번 평가되어야 할 참여 상관 하위 쿼리 - 일반 하위 쿼리 (테이블 식)이 평가되는 동안 한 번 만. 쿼리 플래너는 성능을 최적화 할 수있는 방법
이 있습니다 . 이 관련 답변에는 동일한 문제를 해결하는 코드 예제가 나란히 있습니다.

복귀를 들어 하나 이상의 열을 , A는 LATERAL가입 일반적으로, 간단 깨끗하고 빠릅니다.
또한 상관 된 하위 쿼리와 동등한 내용은 다음과 같습니다 LEFT JOIN LATERAL ... ON true.

에 설명서를 읽으십시오 LATERAL

우리가 여기에 대답 할 것보다 권위가 있습니다.

부질의가 할 수없는 것들

있습니다 A는 것들 LATERAL할 수있는 참여는하지만 (상관 관계) 하위 쿼리는 (쉽게) 할 수 없습니다. 상관 서브 쿼리는 베어 함수 호출 (여러 행을 리턴하면 결과 행을 곱함)을 제외하고 여러 열이 아니라 단일 행만 리턴 할 수 있습니다. 그러나 특정 반환 함수조차도 FROM절 에서만 허용됩니다 . unnest()Postgres 9.4 이상의 여러 매개 변수 와 유사합니다 .매뉴얼 :

이것은 오직 FROM 조항 .

따라서 이것은 작동하지만 하위 쿼리로 쉽게 바꿀 수는 없습니다.

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

절의 쉼표 ( ,) FROM는의 짧은 표기법입니다 CROSS JOIN.
LATERAL테이블 함수에 대해 자동으로 가정됩니다.
특별한 경우에 대한 자세한 내용 UNNEST( array_expression [, ... ] ):

의 반환 기능 SELECT리스트의

리스트 unnest()에서 와 같이 set-returning 기능을 SELECT직접 사용할 수도 있습니다. 이것은 동일한 SELECT목록에서 Postgres 9.6까지 하나 이상의 이러한 기능으로 놀라운 동작을 나타 냈습니다. 그러나 마침내 Postgres 10으로 위생 처리되었으며 현재 표준 SQL이 아니더라도 유효한 대안입니다. 보다:

위의 예를 바탕으로 :

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

비교:

pg 9.6 용 dbfiddle 여기서
pg 10 용 dbfiddle 여기

잘못된 정보를 명확하게

매뉴얼 :

들어 INNEROUTER참여 유형 A는 조건, 즉, 정확히 하나를 지정해야 가입 NATURAL, ON join_condition 또는 USING( join_column를 [...]). 의미는 아래를 참조하십시오.
CROSS JOIN경우이 절 중 어느 것도 나타날 수 없습니다.

따라서이 두 쿼리는 유효합니다 (특히 유용하지는 않지만).

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;

이 것은 아니지만 :

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

그 이유 Andomar의 @ 코드 예제 정확합니다 (이 CROSS JOINA가 조인 조건을 필요로하지 않습니다)와 아틸라의 @ IS 잘못되었습니다.


하위 쿼리가 LATERAL JOIN이 할 수없는 일이 있습니다. 창 기능처럼. 여기
에반 캐롤

@EvanCarroll : 링크에서 상관 하위 쿼리를 찾을 수 없습니다. 그러나 LATERAL하위 쿼리 에서 창 함수를 보여주는 또 다른 답변을 추가했습니다 . gis.stackexchange.com/a/230070/7244
Erwin Brandstetter

1
더 깨끗하고 빠른가? 경우에 따라 더 큰 크기처럼. LATERAL로 전환 한 후 며칠에서 몇 초로 이동 한 쿼리가있었습니다.
rovyko

51

비의 차이 lateral와는 lateral당신이 왼쪽 테이블의 행을 볼 수 있는지 여부에 거짓말을 가입 할 수 있습니다. 예를 들면 다음과 같습니다.

select  *
from    table1 t1
cross join lateral
        (
        select  *
        from    t2
        where   t1.col1 = t2.col1 -- Only allowed because of lateral
        ) sub

이 "외형"은 하위 쿼리가 두 번 이상 평가되어야 함을 의미합니다. 결국 t1.col1많은 값을 가정 할 수 있습니다.

반대로 lateral조인 이 아닌 이후의 하위 쿼리 는 한 번만 평가할 수 있습니다.

select  *
from    table1 t1
cross join
        (
        select  *
        from    t2
        where   t2.col1 = 42 -- No reference to outer query
        ) sub

없이 필요한 lateral경우 내부 쿼리는 외부 쿼리에 의존하지 않습니다. lateral검색어에의 일례이다 correlated때문에 쿼리 자체 행 외부와의 관계, 쿼리.


5
이것은 측면 조인에 대한 가장 깨끗한 설명입니다.
1valdis

설명을 이해하기 쉽게, 감사합니다.
arilwan

어떻게 select * from table1 left join t2 using (col1)비교합니까? / on 조건을 사용하는 조인이 충분하지 않고 측면을 사용하는 것이 더 합리적 인 경우 분명하지 않습니다.
No_name

9

먼저, 측면 및 교차 적용은 동일합니다. 합니다. 따라서 Cross Apply에 대해서도 읽을 수 있습니다. SQL Server에서 오랫동안 구현되었으므로 Lateral에 대한 자세한 정보를 찾을 수 있습니다.

둘째, 내 이해에 따르면 측면을 사용하는 대신 하위 쿼리를 사용하여 수행 할 수있는 것은 없습니다. 그러나:

다음 쿼리를 고려하십시오.

Select A.*
, (Select B.Column1 from B where B.Fk1 = A.PK and Limit 1)
, (Select B.Column2 from B where B.Fk1 = A.PK and Limit 1)
FROM A 

이 조건에서 측면을 사용할 수 있습니다.

Select A.*
, x.Column1
, x.Column2
FROM A LEFT JOIN LATERAL (
  Select B.Column1,B.Column2,B.Fk1 from B  Limit 1
) x ON X.Fk1 = A.PK

이 쿼리에서는 limit 절로 인해 일반 조인을 사용할 수 없습니다. 측면 또는 교차 적용을 사용할 수 있습니다간단한 결합 조건이없는 경우 .

측면 또는 교차 적용에 대한 사용법이 더 있지만 이것이 내가 찾은 가장 일반적인 것입니다.


1
정확히, 왜 PostgreSQL lateral대신을 사용하는지 궁금합니다 apply. 아마도 마이크로 소프트는이 구문을 특허 했습니까?
Andomar

9
@Andomar AFAIK lateral는 SQL 표준에 있지만 apply그렇지 않습니다.
mu는

LEFT JOIN조인 조건 이 필요합니다. ON TRUE어떻게 든 제한하고 싶지 않다면 확인하십시오 .
Erwin Brandstetter

Erwin이 맞습니다. cross join또는 on조건 을 사용하지 않으면 오류가 발생 합니다
Andomar

1
@Andomar :이 잘못된 정보로 인해 나는 또 다른 대답을 추가했습니다.
Erwin Brandstetter

4

아무도 지적하지 않은 것은 LATERAL쿼리를 사용 하여 선택한 모든 행에 사용자 정의 함수를 적용 할 수 있다는 것 입니다.

예를 들어 :

CREATE OR REPLACE FUNCTION delete_company(companyId varchar(255))
RETURNS void AS $$
    BEGIN
        DELETE FROM company_settings WHERE "company_id"=company_id;
        DELETE FROM users WHERE "company_id"=companyId;
        DELETE FROM companies WHERE id=companyId;
    END; 
$$ LANGUAGE plpgsql;

SELECT * FROM (
    SELECT id, name, created_at FROM companies WHERE created_at < '2018-01-01'
) c, LATERAL delete_company(c.id);

이것이 PostgreSQL에서 이런 종류의 작업을 수행하는 방법을 아는 유일한 방법입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.