Różnica między Seek Predicate a Predicate

12

Próbuję dostosować wydajność zapytania, które mamy w SQL Server 2014 Enterprise.

Otworzyłem rzeczywisty plan zapytań w SQL Sentry Plan Explorer i widzę w jednym węźle, że ma on Predykat wyszukiwania, a także Predykat

Jaka jest różnica między Seek Predicate a Predicate ?

wprowadź opis zdjęcia tutaj

Uwaga: Widzę, że istnieje wiele problemów z tym węzłem (np. Wiersze Oszacowane vs. Rzeczywiste, resztkowe IO), ale pytanie nie dotyczy żadnego z nich.

Greg
źródło
3
Predykat wyszukiwania pomaga przy łączeniu, filtrując tylko do wierszy, które znajdują się również w drugiej tabeli (zredagowanej). Predykat (resztkowy predykat) następnie eliminuje wiersze o określonym statusie 2.
Aaron Bertrand
5
Rob Farley stwierdził w komentarzu tutaj :The Seek Predicate can be used to find the start of the RangeScan and then when to stop, while the Predicate is the "check" that is applied to every row in the Range.
Aaron Bertrand

Odpowiedzi:

18

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 PKkolumnie. Jest indeks nieklastrowany, COL1który ma kluczową kolumnę COL1i zawiera COL2.

Rozważ następujące zapytanie:

SELECT *
FROM #174860
WHERE PK >= 15000 AND PK < 15005
AND COL2 = 5000;

Nie używam, BETWEENbo Aaron Bertrand kręci się wokół tego pytania.

W jaki sposób SQL Server powinien optymalizować to zapytanie? Wiem, że włączony filtr PKzmniejszy 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 PKjest orzeczeniem wyszukiwania i COL2jest orzeczeniem.

wprowadź opis zdjęcia tutaj

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:

wprowadź opis zdjęcia tutaj

W takim przypadku SQL Server może wyszukiwać przy użyciu obu kolumn w WHEREklauzuli. 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 COL1kluczowa kolumna. SQL Server może wyszukiwać za pomocą tej kolumny 1000 wierszy o pasującej COL1wartości. Może dalej filtrować te wiersze w COL2kolumnie, aby zmniejszyć ostateczny zestaw wyników do 0 wierszy.

wprowadź opis zdjęcia tutaj

Joe Obbish
źródło