programing

PostgreSQL에서 가로 조인과 하위 쿼리의 차이점은 무엇입니까?

powerit 2023. 5. 8. 22:28
반응형

PostgreSQL에서 가로 조인과 하위 쿼리의 차이점은 무엇입니까?

포스트그레 이후SQL은 다음과 같은 기능을 제공합니다.LATERAL조인스, 저는 현재 팀을 위해 전체 쿼리에 4분 이상 걸리는 비효율적인 하위 쿼리가 많은 복잡한 데이터 덤프를 수행하고 있기 때문에 이에 대해 자세히 읽어보고 있습니다.

는 그것을 합니다.LATERAL조인스가 도움이 될 수도 있지만, 힙 분석에서 와 같은 기사를 읽은 후에도 여전히 잘 이해하지 못합니다.

의 사용 사례는 무엇입니까?LATERAL가입하시겠습니까? A의 차이점은 무엇입니까?LATERAL가입과 하위 질의?

의 개요LATERAL가입하시겠습니까?

이 기능은 Postgre와 함께 도입되었습니다.SQL 9.3.설명서:

하쿼리표에 나타나는 하위 FROM키워드 앞에 올 수 있습니다.LATERAL 앞에 있는 통해이제공열참수있에서 하는 할 수 .FROM (. (미목함항포미)LATERAL는 독립적으로 와 상호 할 수 .FROM항목으)로 됩니다.

함수는 함다표음시다니됩에는수에 됩니다.FROM또한 키워드 앞에 올 수 있습니다.LATERAL 사항입니다.의 " 나함의수경키선는워드사택다니항입우그러▁▁preceding▁다▁by사선니입항▁contain▁the"에서 제공하는 열에 가 포함될 수 있습니다. 함수의 인수는 이전에 제공된 열에 대한 참조를 포함할 수 있습니다.FROM어떤 경우에도 항목

여기에는 기본 코드 예제가 나와 있습니다.

상관된 하위 쿼리에 더 가깝습니다.

A LATERAL조인은 일반 하위 쿼리가 아니라 상관된 하위 쿼리에 더 가깝습니다. 그 표현식은 a의 오른쪽에 있습니다.LATERAL조인은 상관된 하위 쿼리와 마찬가지로 각 행에 대해 한 번씩 평가되는 반면 일반 하위 쿼리(테이블 표현식)는 한 만 평가됩니다. (하지만 쿼리 플래너는 성능을 최적화하는 방법이 있습니다.)
동일한 문제를 해결하는 코드 예제가 나란히 있는 관련 답변:

둘 이상의 열을 반환하는 경우, aLATERAL조인은 일반적으로 더 단순하고, 더 깨끗하고, 더 빠릅니다.
또한 상관된 하위 쿼리의 등가물은 다음과 같습니다.

하위 쿼리에서 수행할 수 없는 작업

어떤 것들이 있습니다.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()에 시대에SELECT직접 열거하다이것은 같은 기능에서 하나 이상의 놀라운 행동을 보여주곤 했습니다.SELECTPostgres 9.6까지 나열합니다.그러나 Postgres 10을 사용하여 최종적으로 삭제되었으며 이제는 표준 SQL이 아니더라도 유효한 대안이 되었습니다.참조:

위의 예를 기반으로 구축:

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

비교:

페이지 9.6에 대한 dbfidle 여기.
여기 페이지 10에 대한 dbfiddle.

잘못된 정보를 명확히 합니다.

설명서:

INNER그리고.OUTER 유형, 조인 지정해야 . 즉, 조인 조건은 "", "", "" 중 입니다.NATURAL,ON join_condition, 또는USING(vmdk_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;
 

그래서 안도마르의 코드 예제가 맞는 것입니다.CROSS JOIN 가입 조건이 필요하지 않음) 및 아틸라의 이라 그렇지 않았습니다.

lateral a 리고a.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쿼리 자체 외부의 행과의 관계로 인해 쿼리를 실행할 수 있습니다.

데이터베이스 테이블

과 같은 다을갖것을 갖는 것.blog플랫폼에서 호스팅하는 블로그를 저장하는 데이터베이스 테이블:

블로그 테이블

또한 현재 두 개의 블로그를 호스팅하고 있습니다.

이드 생성된 제목 URL
1 2013-09-30 블라드 미할체아의 블로그 https://vladmihalcea.com
2 2017-01-22 과민증 https://hypersistence.io

SQL RATAL JOIN을 사용하지 않고 보고서 가져오기

다음 데이터를 추출하는 보고서를 작성해야 합니다.blog테이블:

  • 블로그 아이디
  • 블로그 시대(년 단위)
  • 다음 블로그 기념일 날짜
  • 다음 기념일까지 남은 일수

Postgre를 사용하는 경우SQL을 실행한 후 다음 SQL 쿼리를 실행해야 합니다.

SELECT
  b.id as blog_id,
  extract(
    YEAR FROM age(now(), b.created_on)
  ) AS age_in_years,
  date(
    created_on + (
      extract(YEAR FROM age(now(), b.created_on)) + 1
    ) * interval '1 year'
  ) AS next_anniversary,
  date(
    created_on + (
      extract(YEAR FROM age(now(), b.created_on)) + 1
    ) * interval '1 year'
  ) - date(now()) AS days_to_next_anniversary
FROM blog b
ORDER BY blog_id

보다시피,피시▁the▁as다보,.age_in_years▁the▁you▁calcul▁has다합을 계산할 때 하기 때문에 세 번 .next_anniversary그리고.days_to_next_anniversary가치.

그리고, 바로 거기서 수평 결합이 우리를 도울 수 있습니다.

SQL RATAL JOIN을 사용하여 보고서 가져오기

은 다음관데시다지다니합원음을 합니다.LATERAL JOIN구문:

  • 12c 이후 Oracle
  • 9.3 이후 PostgreSQL
  • 8.0.14 이후의 MySQL

는 SQL Server 다을이할수있다니습을 수 .LATERAL JOIN용사를 CROSS APPLY그리고.OUTER APPLY.

측면 결합을 통해 다음을 재사용할 수 있습니다.age_in_years는 값을 매기고 더 .next_anniversary그리고.days_to_next_anniversary가치.

다음과 같이 이전 쿼리를 다시 작성하여 가로 조인을 사용할 수 있습니다.

SELECT
  b.id as blog_id,
  age_in_years,
  date(
    created_on + (age_in_years + 1) * interval '1 year'
  ) AS next_anniversary,
  date(
    created_on + (age_in_years + 1) * interval '1 year'
  ) - date(now()) AS days_to_next_anniversary
FROM blog b
CROSS JOIN LATERAL (
  SELECT
    cast(
      extract(YEAR FROM age(now(), b.created_on)) AS int
    ) AS age_in_years
) AS t
ORDER BY blog_id

리고그.age_in_years하여 재사용할 수 있습니다.next_anniversary그리고.days_to_next_anniversary계산:

blog_id 나이[나이] 차기의 다음 기념일까지
1 7 2021-09-30 295
2 3 2021-01-22 44

훨씬 낫죠?

age_in_years는 의모 기계다니됩산대해에의 됩니다.blog테이블. 즉, 상관된 하위 쿼리처럼 작동하지만 하위 쿼리 레코드는 기본 테이블과 결합되므로 하위 쿼리에서 생성된 열을 참조할 수 있습니다.

첫째, 가로 방향과 가로 방향 적용은 동일합니다.따라서 교차 적용에 대해서도 읽을 수 있습니다.SQL Server에서 오랫동안 구현되었기 때문에 Rateral보다 자세한 정보를 확인할 수 있습니다.

둘째, 제가 알기로는 횡문법을 사용하는 대신 서브쿼리를 사용하여 할 수 없는 것이 없습니다.그러나:

다음 쿼리를 고려해 보십시오.

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 절 때문에 일반 조인을 사용할 수 없습니다.측면 또는 교차 적용은 간단한 결합 조건이 없을사용할 수 있습니다.

측면 또는 교차 적용을 위한 더 많은 용도가 있지만 이것이 제가 찾은 가장 일반적인 것입니다.

한 는 아도지지않은한가당지사신것다수있입니다는용할무이는적하를 할 수 있다는 것입니다.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);

그게 내가 포스트그레에서 이런 일을 하는 방법을 아는 유일한 방법입니다.SQL.

언급URL : https://stackoverflow.com/questions/28550679/what-is-the-difference-between-a-lateral-join-and-a-subquery-in-postgresql

반응형