Як SQL Server визначає порядок ключових стовпців у відсутніх запитах на індекс?


Відповіді:


44

Коли SQL Server створює відсутність рекомендації щодо індексу для певного плану запитів, він розділяє можливі ключові стовпці на 2 групи. Перший набір містить усі рекомендовані стовпці, які є частиною предиката РІВНІСТЬ. Другий набір містить усі рекомендовані стовпці, що входять до предиката INEQUALITY.

У межах кожного набору стовпці упорядковуються порядковим положенням стовпців, виходячи з визначення таблиці.

(Велике спасибі Бренту Озару за те, що він створив сценарій повторної роботи проти бази даних переповнення стека, щоб довести це!)

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. Наповніть таблиці однаковими даними. Отримайте 100000 рядків з таблиці "Користувачі" за допомогою реального розповсюдження даних.

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 пошуками нерівності

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.