In che modo SQL Server determina l'ordine delle colonne chiave nelle richieste di indice mancanti?


Risposte:


44

Quando SQL Server crea una raccomandazione di indice mancante per un particolare piano di query, separa le possibili colonne chiave in 2 gruppi. Il primo set contiene tutte le colonne consigliate che fanno parte di un predicato EQUALITY. Il secondo set contiene tutte le colonne consigliate che fanno parte di un predicato INEQUALITY.

All'interno di ogni set, le colonne sono ordinate in base alla posizione ordinale delle colonne, in base alla definizione della tabella.

(Mille grazie a Brent Ozar per aver creato uno script repro sul database Stack Overflow per dimostrarlo!)

1. Crea 3 tabelle identiche , ma metti le loro colonne in ordine diverso. (Il motivo qui è utilizzare una varietà di nomi di colonna e tipi di dati per mostrare che ciò non influisce sull'ordine delle colonne nella raccomandazione dell'indice mancante.)

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. Popolare le tabelle con gli stessi dati. Ottieni 100.000 righe dalla tabella Users con la distribuzione dei dati nel mondo reale.

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. Scrivi una query che necessita di un indice. Inizia con 3 filtri di uguaglianza, filtrando per un valore esatto in tutti e 3 i campi. Si noti che tutte e 3 le query hanno gli stessi campi nello stesso ordine:

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

Tutte e tre le tabelle hanno esattamente gli stessi dati e le query sono identiche. L'unica differenza è l'ordine dei campi - e questa è anche la differenza nelle nostre richieste di indice mancanti:

Piani di esecuzione con 3 campi di uguaglianza

Nei piani di esecuzione, l'ordine delle colonne nella richiesta di indice mancante corrisponde esattamente all'ordine delle colonne nella tabella. Ad esempio, in dbo.NumberLetterDate, la colonna numerica è la prima, quindi anche la prima nella richiesta di indice mancante:

  • Su dbo.NumberLetterDate, l'indice mancante è su fINT (numero), fLetter (nvarchar), fDate, lo stesso ordine dei campi nella tabella
  • Su dbo.LetterDateNumber, l'ordine dell'indice passa a fNVARCHAR, fDATE, fINT
  • Su dbo.DateNumberLetter, l'ordine dell'indice passa a fDATE, fINT, fNVARCHAR

Per un'operazione a tabella singola come questa, l'ordine dei campi dell'indice non sembra dipendere dalla selettività, dal tipo di dati o dalla posizione nella query. (Lascio ad altre persone la dimostrazione con domande e join più complessi.)

4. Mescolare in un filtro di disuguaglianza. Nel campo INT, ad esempio, inserisci <> 100 come filtro:

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

Nei piani di esecuzione, i campi di uguaglianza vanno per primi, quindi i campi di disuguaglianza - quindi qui, FINT viene visualizzato per ultimo in tutte e 3 le richieste di indice mancanti perché è una ricerca di disuguaglianza:

Piani di esecuzione con 2 uguaglianza e 1 ricerca di disuguaglianza

5. Utilizzare 3 filtri di disuguaglianza. Usa la stessa ricerca per tutti i campi (<>):

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

Dal momento che non ci sono ricerche sull'uguaglianza, tutti e 3 i campi hanno lo stesso ordine di priorità nella raccomandazione dell'indice mancante e ora torniamo all'ordinamento puramente per ordine di campo:

Piani di esecuzione con 3 ricerche di disuguaglianza

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.