답변:
이것은 약간 광범위하지만 나는 진정한 질문을 이해하고 그에 따라 대답 할 것이라고 생각합니다. 그래도 테이블 대 인덱스 스풀에 대해 이야기하려고합니다. 테이블 스풀과 인덱스 스풀 사이의 선택으로 보는 것이 옳지 않다고 생각합니다. 아시다시피 단일 하위 트리에서 인덱스 스풀, 테이블 스풀 또는 인덱스 스풀과 테이블 스풀을 모두 얻을 수 있습니다. 다음과 같은 조건에서 인덱스 스풀을 얻는 것이 일반적으로 맞습니다.
간단한 데모로 대부분을 볼 수 있습니다. 힙 쌍을 작성하여 시작하십시오.
DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_901;
CREATE TABLE dbo.X_10000_VARCHAR_901 (ID VARCHAR(901) NOT NULL);
INSERT INTO dbo.X_10000_VARCHAR_901 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
DROP TABLE IF EXISTS dbo.X_10000_VARCHAR_800;
CREATE TABLE dbo.X_10000_VARCHAR_800 (ID VARCHAR(800) NOT NULL);
INSERT INTO dbo.X_10000_VARCHAR_800 WITH (TABLOCK)
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
첫 번째 쿼리에는 찾을 것이 없습니다.
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
CROSS JOIN dbo.X_10000_VARCHAR_901 b
OPTION (MAXDOP 1);
따라서 옵티마이 저가 조인을 적용으로 변환 할 이유가 없습니다. 비용 문제로 인해 테이블 스풀이 생깁니다. 따라서이 쿼리는 첫 번째 테스트에 실패합니다.
다음 쿼리에서는 옵티마이 저가 적용을 고려해야 할 이유가 있다고 예상하는 것이 좋습니다.
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID = b.ID
OPTION (LOOP JOIN, MAXDOP 1);
그러나 다음과 같은 의미는 아닙니다.
이 쿼리는 두 번째 테스트에 실패합니다. 자세한 설명은 여기에 있습니다 . 가장 관련성이 높은 부분 인용 :
옵티마이 저는 적용을 가능하게하기 위해 인덱스를 즉석에서 작성하는 것을 고려하지 않습니다. 오히려 이벤트 순서는 일반적으로 반대입니다. 좋은 인덱스가 존재하기 때문에 적용되도록 변환하십시오.
최적화 프로그램이 적용을 고려하도록 쿼리를 다시 작성할 수 있습니다.
SELECT *
FROM dbo.X_10000_VARCHAR_901 a
INNER JOIN dbo.X_10000_VARCHAR_901 b ON a.ID >= b.ID AND a.ID <= b.ID
OPTION (MAXDOP 1);
그러나 여전히 인덱스 스풀이 없습니다.
이 쿼리는 세 번째 테스트에 실패합니다. SQL Server 2014에서 인덱스 키 길이 제한은 900 바이트입니다. 이것은 SQL Server 2016에서 확장되었지만 비 클러스터형 인덱스에만 해당됩니다. 스풀에 대한 인덱스는 클러스터 된 인덱스이므로 한계는 900 바이트로 유지됩니다 . 어쨌든 인덱스 스풀 규칙은 쿼리 실행 중에 오류가 발생할 수 있으므로 적용 할 수 없습니다.
데이터 유형 길이를 800으로 줄이면 마지막으로 인덱스 스풀이있는 계획을 제공합니다.
인덱스 스풀 계획은 당연히 스풀이없는 계획보다 89.7603 대 598.832 대보다 훨씬 저렴합니다. 문서화되지 않은 QUERYRULEOFF BuildSpool
쿼리 힌트 와의 차이점을 확인할 수 있습니다 .
이것은 완전한 대답은 아니지만 희망적으로 당신이 찾고있는 것 중 일부입니다.