Dlaczego liczba wykonań indeksu klastrowanego jest tak wysoka?

15

Mam dwa podobne zapytania, które generują ten sam plan zapytań, z tym wyjątkiem, że jeden plan zapytań wykonuje skanowanie indeksu klastrowanego 1316 razy, podczas gdy drugi wykonuje go 1 raz.

Jedyną różnicą między tymi dwoma zapytaniami są różne kryteria daty. Długotrwałe zapytanie faktycznie zawęża kryteria daty i wycofuje mniej danych.

Zidentyfikowałem niektóre indeksy, które pomogą w obu zapytaniach, ale chcę tylko zrozumieć, dlaczego operator skanowania klastrowanego indeksu wykonuje 1316 razy na zapytaniu, które jest praktycznie takie samo, jak to, w którym wykonuje się 1 raz.

Sprawdziłem statystyki skanowanego PK i są one stosunkowo aktualne.

Oryginalne zapytanie:

select distinct FIR_Incident.IncidentID
from FIR_Incident
left join (
    select incident_id as exported_incident_id
    from postnfirssummary
) exported_incidents on exported_incidents.exported_incident_id = fir_incident.incidentid
where FI_IncidentDate between '2011-06-01 00:00:00.000' and '2011-07-01 00:00:00.000'
    and exported_incidents.exported_incident_id is not null

Generuje ten plan: wprowadź opis zdjęcia tutaj

Po zawężeniu kryteriów zakresu dat:

select distinct FIR_Incident.IncidentID
from FIR_Incident
left join (
    select incident_id as exported_incident_id
    from postnfirssummary
) exported_incidents on exported_incidents.exported_incident_id = fir_incident.incidentid
where FI_IncidentDate between '2011-07-01 00:00:00.000' and '2011-07-02 00:00:00.000'
    and exported_incidents.exported_incident_id is not null

Generuje ten plan: wprowadź opis zdjęcia tutaj

Seibar
źródło
Czy możesz skopiować / wkleić swoje zapytania w bloku kodu zamiast plików obrazów?
Eric Humphrey - lotsahelp
Jasne - dodałem zapytania generujące każdy plan.
Seibar,
W jakiej tabeli występuje skanowanie indeksu klastrowego?
Eric Humphrey - lotsahelp
Skanowanie indeksu klastrowanego znajduje się na podzapytaniu w lewym złączeniu (PostNFIRSS Podsumowanie)
Seibar
1
Przypuszczalnie ostatnim razem, gdy statystyki były aktualizowane, był tylko zero lub jeden wiersz spełniający FI_IncidentDate between '2011-07-01 00:00:00.000' and '2011-07-02 00:00:00.000'kryteria i od tego czasu liczba wstawek w tym zakresie była nieproporcjonalna. Szacuje, że dla tego zakresu dat potrzebne będą tylko 1,07 egzekucji. Nie 1.316, które powstały w rzeczywistości.
Martin Smith,

Odpowiedzi:

9

ŁĄCZENIE po skanie daje wskazówkę: przy mniejszej liczbie wierszy po jednej stronie ostatniego złączenia (oczywiście od prawej do lewej) optymalizator wybiera „zagnieżdżoną pętlę”, a nie „łączenie mieszające”.

Jednak zanim to zobaczę, staram się wyeliminować Wyszukiwanie Kluczowe i ODLEGŁOŚĆ.

  • Kluczowe wyszukiwanie: Twój indeks na FIR_Incident powinien obejmować, prawdopodobnie (FI_IncidentDate, incidentid)lub na odwrót. Lub oba i zobacz, które są używane częściej (oba mogą być)

  • DISTINCTJest konsekwencją LEFT JOIN ... IS NOT NULL. Optymalizator już go usunął (w planach „opuścił pół złączenia” na ostatnim DOŁĄCZU), ale dla jasności użyłbym ISTNIEJ

Coś jak:

select 
    F.IncidentID
from 
    FIR_Incident F
where 
    exists (SELECT * FROM postnfirssummary P
           WHERE P.incident_id = F.incidentid)
    AND
    F.FI_IncidentDate between '2011-07-01 00:00:00.000' and '2011-07-02 00:00:00.000'

Możesz także użyć przewodników po planach i wskazówek JOIN, aby program SQL Server używał funkcji łączenia, ale najpierw spróbuj normalnie działać: przewodnik lub podpowiedź prawdopodobnie nie wytrzymają próby czasu, ponieważ są przydatne tylko dla danych i zapytania uruchamiane teraz, a nie w przyszłości

gbn
źródło