Rzućmy milion wierszy do tabeli tymczasowej wraz z kilkoma kolumnami:
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);
Tutaj mam indeks klastrowy (domyślnie) w PK
kolumnie. Jest indeks nieklastrowany, COL1
który ma kluczową kolumnę COL1
i zawiera COL2
.
Rozważ następujące zapytanie:
SELECT *
FROM #174860
WHERE PK >= 15000 AND PK < 15005
AND COL2 = 5000;
Nie używam, BETWEEN
bo Aaron Bertrand kręci się wokół tego pytania.
W jaki sposób SQL Server powinien optymalizować to zapytanie? Wiem, że włączony filtr PK
zmniejszy zestaw wyników do pięciu wierszy. Serwer SQL może użyć indeksu klastrowego, aby przejść do tych pięciu wierszy zamiast czytać wszystkie miliony wierszy w tabeli. Jednak indeks klastrowany ma tylko kolumnę PK jako kolumnę kluczową. Po wczytaniu wiersza do pamięci należy zastosować filtr COL2
. Tutaj PK
jest orzeczeniem wyszukiwania i COL2
jest orzeczeniem.
Serwer SQL znajduje pięć wierszy za pomocą predykatu wyszukiwania i dodatkowo redukuje te pięć wierszy do jednego wiersza za pomocą normalnego predykatu.
Jeśli inaczej zdefiniuję indeks klastrowany:
CREATE TABLE #174860 (
PK INT NOT NULL,
COL1 INT NOT NULL,
COL2 INT NOT NULL,
PRIMARY KEY (COL2, PK)
);
I uruchom to samo zapytanie, otrzymuję różne wyniki:
W takim przypadku SQL Server może wyszukiwać przy użyciu obu kolumn w WHERE
klauzuli. Dokładnie jeden wiersz jest odczytywany z tabeli przy użyciu kolumn klucza.
Dla jeszcze jednego przykładu rozważ to zapytanie:
SELECT *
FROM #174860
WHERE COL1 = 500
AND COL2 = 3545;
Indeks IX_174860_IX jest indeksem obejmującym, ponieważ zawiera wszystkie kolumny potrzebne do zapytania. Jest to jednak tylko COL1
kluczowa kolumna. SQL Server może wyszukiwać za pomocą tej kolumny 1000 wierszy o pasującej COL1
wartości. Może dalej filtrować te wiersze w COL2
kolumnie, aby zmniejszyć ostateczny zestaw wyników do 0 wierszy.