Mam tabele Log i LogItem; Piszę zapytanie, aby pobrać dane z obu. Istnieją tysiące Logs
i każdy Log
może mieć do 125LogItems
Zapytanie jest skomplikowane, więc pomijam je (jeśli ktoś uważa, że to ważne, prawdopodobnie mogę je opublikować), ale kiedy uruchomiłem plan SSMS Estimated Query, powiedział mi, że nowy indeks nieklastrowany poprawi wydajność nawet o 100% .
Existing Index: Non-clustered
Key Colums (LogItem): ParentLogID, DateModified, Name, DatabaseModified
Query Plan Recommendation
CREATE NONCLUSTERED INDEX [LogReportIndex]
ON [dbo].[LogItem] ([ParentLogID],[DatabaseModified])
Dla zabawy stworzyłem ten nowy indeks i uruchomiłem zapytanie. Ku mojemu zdziwieniu, moje zapytanie działa teraz około 1 sekundy, zanim było ponad 10 sekund.
Zakładałem, że mój istniejący indeks obejmowałby to nowe zapytanie, więc moje pytanie brzmi: dlaczego utworzenie nowego indeksu dla jedynych kolumn użytych w moim nowym zapytaniu poprawiło wydajność? Czy powinienem mieć indeks dla każdej unikalnej kombinacji kolumn używanych w moich where
klauzulach?
Uwaga: Nie sądzę, że dzieje się tak, ponieważ SQL Server buforuje moje wyniki, uruchomiłem zapytanie około 25-30 razy, zanim utworzyłem indeks, i konsekwentnie zajęło to 10-15 sekund, po indeksie jest teraz konsekwentnie ~ 1 lub mniej.
źródło
Odpowiedzi:
Ważna jest kolejność kolumn w indeksie. Jeśli filtrowanie wymaga kolumny 1 i 4 z indeksu, indeks nie pomoże. Jest to przydatne tylko podczas filtrowania według pierwszych N kolejnych kolumn.
Wynika to z faktu, że indeks jest drzewem. Nie można skutecznie wybrać wszystkich węzłów drzewa
column3 = something
, ponieważ, ponieważ są one rozproszone po wszystkich innych miejscach, należących do różnych wartościcolumn1
icolumn2
. Ale jeśli wieszcolumn1
icolumn2
tak, znalezienie odpowiedniej gałęzi na drzewie nie jest żadnym problemem.źródło
where
s mogą się nakładać, więc możesz mieć indeks, który ładnie obejmuje kilkawhere
s; lub możesz zignorować częśćwhere
klauzuli, ponieważ indeksowanie w określonej kolumnie i tak nie pomoże (niska selektywność); ale ogólnie tak.where
klauzulach nie jest ważna. Serwer zawsze zorganizuje je tak, aby jak najlepiej wykorzystać istniejące indeksy. To tylko kwestia posiadania indeksu zawierającego wszystkie wymaganewhere
kolumny jako pierwsze kolumny.Krawędź natarcia indeksu jest to, co się liczy.
Dopóki twoje zapytanie jest „objęte” wiodącą krawędzią indeksu, będzie wydajne. Indeksy baz danych są zazwyczaj implementowane jako B-Drzewa, a struktura B-Drzewa nakazuje, aby wyszukiwanie odbywało się w określonej kolejności, dlatego kolejność pól w indeksie złożonym ma znaczenie.
Jeśli masz „dziury”, np. Jeśli wyszukujesz
ParentLogID
iDatabaseModified
indeks jest włączony{ParentLogID, DateModified, Name, DatabaseModified}
, ale tylko{ParentLogID}
część indeksu można efektywnie wykorzystać.(UWAGA: Niektóre DBMS mogą wykorzystać tę
{DatabaseModified}
część poprzez „pominięcie skanowania”, ale nawet jeśli DBMS to robi, jest to znacznie mniej wydajne niż zwykły dostęp do indeksu) .źródło
Columns (a, b, c, d, e, f)
i większość zapytań jest... WHERE A IN(...) AND B = 3
moim indeksemIndex(a,b,c,d)
, to jest dobry, ale to nie pomaga, jeśli tak,... WHERE A IN (...) AND D = 5
dlatego właśnie mój nowy indeks, który utworzyłem,Index(a,d)
poprawił tak bardzo wydajność, prawda?