대상 테이블에 아직없는 경우에만 소스 테이블에서 행을 삽입하는 다음 쿼리를 고려하십시오.
INSERT INTO dbo.HALLOWEEN_IS_COMING_EARLY_THIS_YEAR WITH (TABLOCK)
SELECT maybe_new_rows.ID
FROM dbo.A_HEAP_OF_MOSTLY_NEW_ROWS maybe_new_rows
WHERE NOT EXISTS (
SELECT 1
FROM dbo.HALLOWEEN_IS_COMING_EARLY_THIS_YEAR halloween
WHERE maybe_new_rows.ID = halloween.ID
)
OPTION (MAXDOP 1, QUERYTRACEON 7470);
하나의 가능한 계획 형태에는 병합 조인 및 열성적인 스풀이 포함됩니다. 할로윈 문제 를 해결하기 위해 열망하는 스풀 연산자가 있습니다 .
내 컴퓨터에서 위 코드는 약 6900ms 안에 실행됩니다. 테이블을 작성하는 Repro 코드는 질문 맨 아래에 포함되어 있습니다. 성능에 만족하지 않으면 열망 스풀에 의존하지 않고 임시 테이블에 삽입 할 행을로드하려고 시도 할 수 있습니다. 가능한 구현은 다음과 같습니다.
DROP TABLE IF EXISTS #CONSULTANT_RECOMMENDED_TEMP_TABLE;
CREATE TABLE #CONSULTANT_RECOMMENDED_TEMP_TABLE (
ID BIGINT,
PRIMARY KEY (ID)
);
INSERT INTO #CONSULTANT_RECOMMENDED_TEMP_TABLE WITH (TABLOCK)
SELECT maybe_new_rows.ID
FROM dbo.A_HEAP_OF_MOSTLY_NEW_ROWS maybe_new_rows
WHERE NOT EXISTS (
SELECT 1
FROM dbo.HALLOWEEN_IS_COMING_EARLY_THIS_YEAR halloween
WHERE maybe_new_rows.ID = halloween.ID
)
OPTION (MAXDOP 1, QUERYTRACEON 7470);
INSERT INTO dbo.HALLOWEEN_IS_COMING_EARLY_THIS_YEAR WITH (TABLOCK)
SELECT new_rows.ID
FROM #CONSULTANT_RECOMMENDED_TEMP_TABLE new_rows
OPTION (MAXDOP 1);
새로운 코드는 약 4400ms 안에 실행됩니다. 실제 계획을 세우고 Actual Time Statistics ™을 사용하여 운영자 수준에서 시간이 소비되는 위치를 조사 할 수 있습니다. 실제 계획을 요청하면 이러한 쿼리에 상당한 오버 헤드가 발생하므로 총계가 이전 결과와 일치하지 않습니다.
╔═════════════╦═════════════╦══════════════╗
║ operator ║ first query ║ second query ║
╠═════════════╬═════════════╬══════════════╣
║ big scan ║ 1771 ║ 1744 ║
║ little scan ║ 163 ║ 166 ║
║ sort ║ 531 ║ 530 ║
║ merge join ║ 709 ║ 669 ║
║ spool ║ 3202 ║ N/A ║
║ temp insert ║ N/A ║ 422 ║
║ temp scan ║ N/A ║ 187 ║
║ insert ║ 3122 ║ 1545 ║
╚═════════════╩═════════════╩══════════════╝
열망 스풀이있는 쿼리 계획은 임시 테이블을 사용하는 계획에 비해 삽입 및 스풀 연산자에 훨씬 더 많은 시간을 소비하는 것으로 보입니다.
임시 테이블이있는 계획이 더 효율적인 이유는 무엇입니까? 어쨌든 간절한 스풀은 대부분 내부 임시 테이블이 아닌가? 나는 내부에 중점을 둔 답변을 찾고 있다고 생각합니다. 통화 스택이 어떻게 다른지 알 수 있지만 큰 그림을 파악할 수는 없습니다.
누군가 알고 싶어하는 경우 SQL Server 2017 CU 11을 사용하고 있습니다. 위 쿼리에 사용 된 테이블을 채우는 코드는 다음과 같습니다.
DROP TABLE IF EXISTS dbo.HALLOWEEN_IS_COMING_EARLY_THIS_YEAR;
CREATE TABLE dbo.HALLOWEEN_IS_COMING_EARLY_THIS_YEAR (
ID BIGINT NOT NULL,
PRIMARY KEY (ID)
);
INSERT INTO dbo.HALLOWEEN_IS_COMING_EARLY_THIS_YEAR WITH (TABLOCK)
SELECT TOP (20000000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
CROSS JOIN master..spt_values t3
OPTION (MAXDOP 1);
DROP TABLE IF EXISTS dbo.A_HEAP_OF_MOSTLY_NEW_ROWS;
CREATE TABLE dbo.A_HEAP_OF_MOSTLY_NEW_ROWS (
ID BIGINT NOT NULL
);
INSERT INTO dbo.A_HEAP_OF_MOSTLY_NEW_ROWS WITH (TABLOCK)
SELECT TOP (1900000) 19999999 + ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;