SQL Server는 누락 된 인덱스 요청에서 키 열 순서를 어떻게 결정합니까?


답변:


44

SQL Server가 특정 쿼리 계획에 대해 누락 된 인덱스 권장 사항을 만들면 가능한 키 열을 두 그룹으로 분리합니다. 첫 번째 세트에는 EQUALITY 술어의 일부인 모든 권장 컬럼이 포함됩니다. 두 번째 세트에는 INEQUALITY 술어의 일부인 모든 권장 열이 포함됩니다.

각 집합 내에서 열은 테이블 정의에 따라 열의 서수 위치에 따라 정렬됩니다.

(이를 증명하기 위해 Stack Overflow 데이터베이스에 대해 재현 스크립트를 작성해 주신 Brent Ozar에게 감사드립니다!)

1. 3 개의 동일한 테이블을 작성 하지만 열을 다른 순서로 놓으십시오. (여기서 누락 된 인덱스 권장 사항에서 열 순서에 영향을 미치지 않음을 나타 내기 위해 다양한 열 이름과 데이터 유형을 사용하기 때문입니다.)

CREATE TABLE dbo.NumberLetterDate (ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, 
fINT INT, fNVARCHAR NVARCHAR(40), fDATE DATETIME, AboutMe NVARCHAR(MAX));
GO
CREATE TABLE dbo.LetterDateNumber (ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, 
fNVARCHAR NVARCHAR(40), fDATE DATETIME, fINT INT, AboutMe NVARCHAR(MAX));
GO
CREATE TABLE dbo.DateNumberLetter (ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
fDATE DATETIME, fINT INT, fNVARCHAR NVARCHAR(40), AboutMe NVARCHAR(MAX));
GO

2. 동일한 데이터로 테이블을 채 웁니다. 실제 데이터 배포를 통해 Users 테이블에서 100,000 개의 행을 가져옵니다.

INSERT INTO dbo.NumberLetterDate(fINT, fNVARCHAR, fDATE, AboutMe)
SELECT TOP 100000 Age, DisplayName, LastAccessDate, AboutMe
  FROM dbo.Users WITH (NOLOCK)
  ORDER BY Id;
GO
INSERT INTO dbo.LetterDateNumber(fINT, fNVARCHAR, fDATE, AboutMe)
SELECT TOP 100000 Age, DisplayName, LastAccessDate, AboutMe
  FROM dbo.Users WITH (NOLOCK)
  ORDER BY Id;
GO
INSERT INTO dbo.DateNumberLetter(fINT, fNVARCHAR, fDATE, AboutMe)
SELECT TOP 100000 Age, DisplayName, LastAccessDate, AboutMe
  FROM dbo.Users WITH (NOLOCK)
  ORDER BY Id;
GO

3. 인덱스가 필요한 쿼리를 작성하십시오. 3 개의 등식 필터로 시작하여 3 개의 모든 필드에서 정확한 값을 필터링하십시오. 3 개의 쿼리는 모두 같은 순서로 동일한 필드를 갖습니다.

SELECT ID
  FROM dbo.NumberLetterDate
  WHERE fINT = 100
  AND fNVARCHAR = 'Brent Ozar'
  AND fDATE = '2018/01/01'
  AND 1 = (SELECT 1);

SELECT ID
  FROM dbo.LetterDateNumber
  WHERE fINT = 100
  AND fNVARCHAR = 'Brent Ozar'
  AND fDATE = '2018/01/01'
  AND 1 = (SELECT 1);

SELECT ID
  FROM dbo.DateNumberLetter
  WHERE fINT = 100
  AND fNVARCHAR = 'Brent Ozar'
  AND fDATE = '2018/01/01'
  AND 1 = (SELECT 1);
GO

세 테이블 모두 정확히 동일한 데이터를 가지며 쿼리는 동일합니다. 유일한 차이점은 필드 순서이며, 누락 된 인덱스 요청의 차이점이기도합니다.

3 개의 동등 필드를 가진 실행 계획

실행 계획에서 누락 된 인덱스 요청의 열 순서는 테이블의 열 순서와 정확히 일치합니다. 예를 들어 dbo.NumberLetterDate에서 숫자 열이 첫 번째이므로 누락 된 인덱스 요청에서도 첫 번째 열입니다.

  • dbo.NumberLetterDate에서 누락 된 인덱스는 테이블의 필드 순서와 동일한 fINT (숫자), fLetter (nvarchar), fDate입니다.
  • dbo.LetterDateNumber에서 인덱스 순서는 fNVARCHAR, fDATE, fINT로 전환됩니다.
  • dbo.DateNumberLetter에서 인덱스 순서는 fDATE, fINT, fNVARCHAR로 전환됩니다.

이와 같은 단일 테이블 작업의 경우 인덱스 필드 순서는 쿼리의 선택성, 데이터 유형 또는 위치에 따라 달라지지 않습니다. (나는 더 복잡한 쿼리 및 조인으로 이것을 증명하기 위해 다른 사람들에게 맡깁니다.)

4. 불평등 필터를 혼합하십시오. 예를 들어, INT 필드에서 필터로 <> 100을 입력하십시오.

SELECT ID
  FROM dbo.NumberLetterDate
  WHERE fINT <> 100
  AND fNVARCHAR = 'Brent Ozar'
  AND fDATE = '2018/01/01'
  AND 1 = (SELECT 1);

SELECT ID
  FROM dbo.LetterDateNumber
  WHERE fINT <> 100
  AND fNVARCHAR = 'Brent Ozar'
  AND fDATE = '2018/01/01'
  AND 1 = (SELECT 1);

SELECT ID
  FROM dbo.DateNumberLetter
  WHERE fINT <> 100
  AND fNVARCHAR = 'Brent Ozar'
  AND fDATE = '2018/01/01'
  AND 1 = (SELECT 1);
GO

실행 계획에서 항등 필드가 먼저 시작한 다음 부등식 필드가 시작됩니다. 따라서 여기서는 fINT가 부등호 검색이므로 누락 된 3 개의 인덱스 요청 모두에서 마지막으로 표시됩니다.

2 개의 평등 및 1 개의 불평등 검색으로 실행 계획

5. 3 개의 불평등 필터를 사용하십시오. 모든 필드에 동일한 검색을 사용하십시오 (<>).

SELECT ID
  FROM dbo.NumberLetterDate
  WHERE fINT <> 100
  AND fNVARCHAR <> 'Brent Ozar'
  AND fDATE <> '2018/01/01'
  AND 1 = (SELECT 1);

SELECT ID
  FROM dbo.LetterDateNumber
  WHERE fINT <> 100
  AND fNVARCHAR <> 'Brent Ozar'
  AND fDATE <> '2018/01/01'
  AND 1 = (SELECT 1);

SELECT ID
  FROM dbo.DateNumberLetter
  WHERE fINT <> 100
  AND fNVARCHAR <> 'Brent Ozar'
  AND fDATE <> '2018/01/01'
  AND 1 = (SELECT 1);
GO

항등 검색이 없기 때문에 누락 된 인덱스 권장 사항에서 3 개의 필드 모두 우선 순위가 동일하며, 이제는 필드 순서를 기준으로 순수한 정렬로 돌아갑니다.

3 개의 불평등 검색으로 실행 계획

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