OUTER JOIN 내에 중첩 된 INNER JOIN의 구문 대 쿼리 결과


10

TLDR; 두 가지 실행 계획을 살펴보면 어느 쪽이 더 나은지에 대한 쉬운 대답이 있습니까? 의도적으로 인덱스를 만들지 않았으므로 무슨 일이 일어나고 있는지 쉽게 알 수 있습니다.

다른 조인 스타일 (예 : 중첩 대 기존) 간의 쿼리 성능 차이를 발견 한 이전 질문 에 이어 중첩 구문도 쿼리 동작을 수정한다는 것을 알았습니다. 다음 두 가지 쿼리를 고려하십시오.

SELECT  a.*, m.*, n.*
FROM    dbo.Autos a
LEFT JOIN dbo.Models m
  JOIN dbo.Manufacturers n  -- <-- Nested INNER JOIN
  ON n.ManufacturerID = m.ManufacturerID
ON m.ModelID = a.ModelID

여기에 이미지 설명을 입력하십시오

Models 테이블에 없는 ModelID를 가진 자동 행을 포함시키기 위해 제조업체를 조인 할 필요는 없습니다 .

여기에 이미지 설명을 입력하십시오

전통적인 구문을 사용하여 Manufactures에 대한 조인을 외부 조인으로 변경해야하지만 쿼리 계획이 변경됩니다.

SELECT a.*, m.*, n.*
FROM dbo.Autos a
LEFT JOIN dbo.Models m
ON m.ModelID = a.ModelID
LEFT JOIN dbo.Manufacturers n -- <-- Now LEFT OUTER JOIN
ON n.ManufacturerID = m.ManufacturerID

여기에 이미지 설명을 입력하십시오

답변:


12

두 가지 실행 계획을 살펴보면 어느 쪽이 더 나은지에 대한 쉬운 대답이 있습니까? 의도적으로 인덱스를 만들지 않았으므로 무슨 일이 일어나고 있는지 쉽게 알 수 있습니다.

두 번째 계획은 추정 비용이 더 낮기 때문에 제한된 의미에서 '더 나은'것입니다.

데이터 세트가 너무 작아서 옵티마이 저가 대안을 찾는 데 많은 시간을 소비하지 않았습니다. 쿼리의 첫 번째 형태는 초기에 해시 조인과 테이블 스풀을 사용하여 계획을 찾는 것입니다. 해당 계획의 예상 비용이 너무 낮아서 옵티마이 저가 더 나은 것을 찾지 않아도됩니다.

쿼리의 두 번째 형식은 검색 프로세스 초기에 중첩 루프 외부 조인 만 사용하여 계획을 찾고 다시 옵티마이 저가 계획이 충분하다고 결정합니다. 이 계획은 더 싼 것으로 추정됩니다.

(질문 의견에서 언급했듯이) 두 쿼리는 의미 상 동일하지 않습니다. 결과가 데이터베이스의 모든 가능한 미래 상태에 대해 항상 동일하다는 것을 보장 할 수 있지만 옵티마이 저가 그러한 가정을 할 수없는 경우에는 이것이 중요하지 않을 수 있습니다. 모든 상황에서 SQL에 지정된 것과 동일한 결과를 생성하도록 보장 된 계획 만 생성합니다.

중첩 구문도 쿼리 동작을 수정한다는 것을 알았습니다.

'중첩 구문'은 전체 ANSI 조인 구문 사양의 한 측면 일뿐입니다. 보다 복잡한 조인 패턴에 대해 전체 논리적 사양을 사용하려면 사양에서 괄호 및 FROM절 하위 쿼리를 허용합니다 (선택 사항) .

괄호를 사용하여 동일한 ANSI 구문을 사용 하여 쿼리를 작성할 수 있습니다 .

SELECT
    A.*,
    M.*,
    N.* 
FROM dbo.Autos AS A
LEFT JOIN
(
    dbo.Manufacturers AS N
    JOIN dbo.Models AS M
        ON M.ManufacturerID = N.ManufacturerID
) ON M.ModelID = A.ModelID;

이 양식 논리적 인 요구 사항은 왼쪽에서 가입하는 것을 명확하게 보여줍니다 Autos받는 결과를 내면 가입 ManufacturersModels. 선택적 괄호를 생략하면 '중첩'이라는 형식이됩니다.

SELECT
    A.*,
    M.*,
    N.* 
FROM dbo.Autos AS A
LEFT JOIN dbo.Manufacturers AS N
JOIN dbo.Models AS M
    ON M.ManufacturerID = N.ManufacturerID
    ON M.ModelID = A.ModelID;

이것은 다른 구문이 아닙니다. 선택적인 괄호를 생략하고 조금 다시 포맷하는 것입니다.

Martin이 언급했듯이이 경우 내부 조인과 오른쪽 외부 조인을 사용하여 논리적 요구 사항을 표현할 수도 있습니다.

SELECT
    A.*,
    M.*,
    N.* 
FROM dbo.Manufacturers AS N
JOIN dbo.Models AS M
    ON M.ManufacturerID = N.ManufacturerID
RIGHT JOIN dbo.Autos AS A
    ON A.ModelID = M.ModelID;

위의 세 가지 쿼리 형식은 모두 동일한 ANSI 조인 구문을 사용합니다. 세 가지 모두 제공된 데이터 세트를 사용하여 동일한 물리적 실행 계획을 생성합니다.

일반적인 실행 계획

이전 질문에 대한 답변에서 언급했듯이 정확히 동일한 논리적 요구 사항을 나타내는 쿼리가 항상 동일한 실행 계획을 생성하지는 않습니다. 어떤 논리 쿼리 형식을 선호 하는가는 주로 스타일 문제입니다. 하나의 특정 스타일과 '더 나은'쿼리 계획 간에는 일반적으로 상관 관계가 없습니다. 새 쿼리가 실제로 원래 쿼리와 동일하지 않은 경우 특정 계획을 얻기 위해 쿼리를 다시 작성하지 않는 것이 좋습니다.

SQL 표준은 FROM절 하위 쿼리 도 허용 하므로 동일한 쿼리 사양을 작성하는 또 다른 방법은 다음과 같습니다.

SELECT * 
FROM dbo.Autos AS A
LEFT JOIN
(
    SELECT
        N.ManufacturerID,
        ManufacturerName = N.Name,
        M.ModelID,
        ModelName = M.Name
    FROM dbo.Manufacturers AS N
    JOIN dbo.Models AS M
        ON M.ManufacturerID = N.ManufacturerID
) AS R1
    ON R1.ModelID = A.ModelID;

전통적인 구문을 사용하여`제조업체의 조인을 외부 조인으로 변경해야합니다.하지만 쿼리 계획이 변경됩니다.

이것은 아마도 쿼리의 의미를 바꿀 것입니다.이 경우 기술적으로 유효한 대안이 아닙니다 (그러나 귀하의 질문에 대한 ypercube의견 참조 ).

ANSI 조인 구문의 (선택적) 괄호는 이와 같이보다 복잡한 조인 요구 사항에 정확하게 적용되므로 필요한 경우이를 사용하는 것을 두려워해서는 안됩니다.

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