Lanciamo un milione di righe in una tabella temporanea insieme ad alcune colonne:
CREATE TABLE #174860 (
PK INT NOT NULL,
COL1 INT NOT NULL,
COL2 INT NOT NULL,
PRIMARY KEY (PK)
);
INSERT INTO #174860 WITH (TABLOCK)
SELECT RN
, RN % 1000
, RN % 10000
FROM
(
SELECT TOP 1000000 ROW_NUMBER () OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values v1,
master..spt_values v2
) t;
CREATE INDEX IX_174860_IX ON #174860 (COL1) INCLUDE (COL2);
Qui ho un indice cluster (per impostazione predefinita) sulla PK
colonna. C'è un indice non cluster su COL1
che ha una colonna chiave COL1
e include COL2
.
Considera la seguente query:
SELECT *
FROM #174860
WHERE PK >= 15000 AND PK < 15005
AND COL2 = 5000;
Qui non sto usando BETWEEN
perché Aaron Bertrand è in giro per questa domanda.
In che modo SQL Server Optimizer dovrebbe eseguire questa query? Bene, so che il filtro attivo PK
ridurrà il set di risultati a cinque righe. Il server SQL può utilizzare l'indice cluster per passare a queste cinque righe anziché leggere tutti i milioni di righe nella tabella. Tuttavia, l'indice cluster ha solo la colonna PK come colonna chiave. Dopo aver letto la riga in memoria, è necessario applicare il filtro COL2
. Qui, PK
è un predicato di ricerca ed COL2
è un predicato.
Il server SQL trova cinque righe usando il predicato seek e riduce ulteriormente quelle cinque righe a una riga con il predicato normale.
Se definisco l'indice cluster in modo diverso:
CREATE TABLE #174860 (
PK INT NOT NULL,
COL1 INT NOT NULL,
COL2 INT NOT NULL,
PRIMARY KEY (COL2, PK)
);
Ed eseguo la stessa query ottengo risultati diversi:
In questo caso, SQL Server può cercare utilizzando entrambe le colonne nella WHERE
clausola. Esattamente una riga viene letta dalla tabella usando le colonne chiave.
Per un altro esempio, considera questa query:
SELECT *
FROM #174860
WHERE COL1 = 500
AND COL2 = 3545;
L'indice IX_174860_IX è un indice di copertura perché contiene tutte le colonne necessarie per la query. Tuttavia, COL1
è solo una colonna chiave. SQL Server può cercare con quella colonna per trovare le 1000 righe con un COL1
valore corrispondente . Può inoltre filtrare ulteriormente quelle righe sulla COL2
colonna per ridurre il risultato finale impostato su 0 righe.