다른 유형의 스풀을 선택하는 옵티 마이저에는 어떤 비용 요소가 있습니까?


15

스 풀럼

SQL Server에는 여러 종류의 스풀이 있습니다. 내가 관심이 있다는이는 표 스풀 의 및 인덱스 스풀 , 수정 쿼리의 외부 .

특히 중첩 루프 조인의 내부에서 읽기 전용 쿼리는 테이블 또는 인덱스 스풀을 사용하여 잠재적으로 I / O를 줄이고 쿼리 성능을 향상시킬 수 있습니다. 이 스풀은 Eager 또는 Lazy 일 수 있습니다 . 당신과 나처럼

내 질문은 :

  • Table vs. Index Spool을 선택할 때 고려해야 할 요소
  • Eager와 Lazy Spools 중에서 어떤 요소를 선택해야합니까?

답변:


12

이것은 약간 광범위하지만 나는 진정한 질문을 이해하고 그에 따라 대답 할 것이라고 생각합니다. 그래도 테이블 대 인덱스 스풀에 대해 이야기하려고합니다. 테이블 스풀과 인덱스 스풀 사이의 선택으로 보는 것이 옳지 않다고 생각합니다. 아시다시피 단일 하위 트리에서 인덱스 스풀, 테이블 스풀 또는 인덱스 스풀과 테이블 스풀을 모두 얻을 수 있습니다. 다음과 같은 조건에서 인덱스 스풀을 얻는 것이 일반적으로 맞습니다.

  1. 쿼리 최적화 프로그램에서 조인을 적용으로 변환해야하는 이유가 있습니다.
  2. 쿼리 최적화 프로그램은 실제로 적용에 대한 변환을 수행합니다.
  3. 쿼리 최적화 프로그램은 규칙을 사용하여 인덱스 스풀을 추가합니다 (최소 인덱스 스풀은 사용하기에 안전해야 함)
  4. 인덱스 스풀이있는 계획이 선택되었습니다.

간단한 데모로 대부분을 볼 수 있습니다. 힙 쌍을 작성하여 시작하십시오.

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쿼리 힌트 와의 차이점을 확인할 수 있습니다 .

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

이것은 완전한 대답은 아니지만 희망적으로 당신이 찾고있는 것 중 일부입니다.

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