이 Constant Scan 및 Left Outer Join은 간단한 SELECT 쿼리 계획에서 어디에서 왔습니까?


21

나는이 테이블을 가지고있다 :

CREATE TABLE [dbo].[Accounts] (
    [AccountId] UNIQUEIDENTIFIER UNIQUE NOT NULL DEFAULT NEWID(),
    -- WHATEVER other columns
);
GO
CREATE UNIQUE CLUSTERED INDEX [AccountsIndex]
    ON [dbo].[Accounts]([AccountId] ASC);
GO

이 쿼리 :

DECLARE @result UNIQUEIDENTIFIER
SELECT @result = AccountId FROM Accounts WHERE AccountId='guid-here'

예상대로 단일 인덱스 검색으로 구성된 쿼리 계획으로 실행합니다.

SELECT <---- Clustered Index Seek

이 쿼리는 동일한 작업을 수행합니다.

DECLARE @result UNIQUEIDENTIFIER
SET @result = (SELECT AccountId FROM Accounts WHERE AccountId='guid-here')

그러나 Index Seek의 결과가 Outer Outer Joined 된 Constant Scan 결과와 함께 계산 스칼라에 공급되는 계획으로 실행됩니다.

SELECT <--- Compute Scalar <--- Left Outer Join <--- Constant Scan
                                      ^
                                      |------Clustered Index Seek

그 여분의 마술은 무엇입니까? Constant Scan 다음에 Left Outer Join이 수행하는 작업은 무엇입니까?

답변:


29

두 문장의 의미는 다릅니다 :

  • 첫 번째 행은 행이 없으면 변수 값을 설정하지 않습니다.
  • 두 번째는 행을 찾을 수 없으면 항상 null을 포함하여 변수를 설정합니다.

상수 스캔은 빈 행 (열이 없음!)을 생성하여 기본 테이블과 일치하지 않는 경우 변수가 업데이트됩니다. 왼쪽 조인은 빈 행이 조인을 유지합니다. 변수 할당은 실행 계획의 루트 노드에서 발생하는 것으로 생각할 수 있습니다.

사용 SELECT @result

-- Set initial value
DECLARE @result uniqueidentifier = {guid 'FE2CA909-1162-4C6C-A7AC-33B257E28539'};

-- @result does not change
SELECT @result = AccountId 
FROM Accounts 
WHERE AccountId={guid '7AD4D33C-1ED7-4183-B7F3-48C33D666525'};

SELECT @result;

결과 1

사용 SET @result

-- Set initial value
DECLARE @result uniqueidentifier = {guid 'FE2CA909-1162-4C6C-A7AC-33B257E28539'};

-- @result set to null
SET @result = 
(
    SELECT AccountId 
    FROM Accounts 
    WHERE AccountId={guid '7AD4D33C-1ED7-4183-B7F3-48C33D666525'}
);

SELECT @result;

결과 2

실행 계획

과제 할당루트 노드에 행이 도착하지 않으므로 할당이 발생하지 않습니다.

SET 할당행은 항상 루트 노드에 도착하므로 변수 지정이 발생합니다.


여분의 Constant Scan 및 Nested Loops Left Outer Join은 신경 쓰지 않아도됩니다. 특히 조인은 외부 입력에서 하나의 행과 내부 입력에서 최대 하나의 행 (예 : 한 행)이 발생하기 때문에 저렴합니다.

변수 할당이 발생하도록 하위 쿼리에서 행이 생성되도록하는 다른 방법이 있습니다. 하나는 중복 스칼라 집계 (그룹 별 절 없음)를 사용하는 것입니다.

-- Set initial value
DECLARE @result uniqueidentifier = {guid 'FE2CA909-1162-4C6C-A7AC-33B257E28539'};

-- @result set to null
SET @result = 
    (
        SELECT MAX(AccountId)
        FROM Accounts 
        WHERE AccountId={guid '7AD4D33C-1ED7-4183-B7F3-48C33D666525'} 
    );
SELECT @result;

결과 3

스칼라 집계 실행 계획

스칼라 집계는 입력을받지 않아도 행을 생성합니다.

선적 서류 비치:

SELECT 문이 행을 리턴하지 않으면 변수는 현재 값을 유지합니다. expression이 값을 리턴하지 않는 스칼라 서브 쿼리 인 경우 변수는 NULL로 설정됩니다.

변수를 할당하려면 SELECT @local_variable 대신 SET @local_variable을 사용하는 것이 좋습니다.

더 읽을 거리 :

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