不足しているインデックスリクエストでSQL Serverはキー列の順序をどのように決定しますか?


回答:


44

SQL Serverは、特定のクエリプランに対して不足しているインデックスの推奨事項を作成するときに、可能なキー列を2つのグループに分けます。最初のセットには、EQUALITY述部の一部である推奨列がすべて含まれています。2番目のセットには、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つのテーブルはすべてまったく同じデータを持ち、クエリは同一です。唯一の違いはフィールドの順序です。これは、欠落しているインデックスリクエストの違いでもあります。

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.