Reguła twarda i szybka dla uwzględnienia kolumn w indeksie

38

Czy istnieje jakaś twarda i szybka reguła, która decyduje o tym, w których kolumnach i jakiej kolejności należy je umieścić Uwzględnione w indeksie nieklastrowanym. Właśnie czytałem ten post https://stackoverflow.com/questions/1307990/why-use-the-include-clause-when-creating-an-index i znalazłem to dla następującego zapytania:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5

Plakat sugeruje, aby zrobić indeks w ten sposób:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(EmployeeID, DepartmentID)
  INCLUDE (Lastname)

oto moje pytanie, dlaczego nie możemy zrobić takiego indeksu

CREATE NONCLUSTERED INDEX NC_EmpDep 
      ON Employee( EmployeeID, DepartmentID, LastName)

lub

    CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)

i co powoduje, że plakat decyduje się na uwzględnienie kolumny LastName. Dlaczego nie inne kolumny? i jak zdecydować, w jakiej kolejności powinniśmy przechowywać tam kolumny?

Społeczność
źródło
3
ZAWIERAJĄ zwykle pole, które będzie potrzebne PO znalezieniu rekordu, oszczędzając ci podróży powrotnej w obie strony, aby uzyskać więcej danych. Kolejność pól w polu INCLUDE nie jest ważna.
Jimbo
Ryk, osobiście uważam ten post za pomocny.
Jason Young,
Uważam również, że to pytanie jest pomocne. Skoncentrujmy się na dobrych pytaniach i dobrych odpowiedziach zamiast prześladować osoby ...
Volvox

Odpowiedzi:

47

Ta sugestia indeksu autorstwa marc_s jest błędna. Dodałem komentarz. (I to była też moja odpowiedź zaakceptowana!)

Indeks dla tego zapytania to

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (Lastname, EmployeeID)

Indeks jest zazwyczaj

CREATE INDEX <name> ON <table> (KeyColList) INCLUDE (NonKeyColList)

Gdzie:

  • KeyColList = Kolumny kluczowe = używane do ograniczania wierszy i przetwarzania
    GDZIE, DOŁĄCZ, ORDER BY, GROUP BY itp.
  • NonKeyColList = Kolumny niekluczowe = używane w SELECT i agregacji (np. SUM (col)) po selekcji / ograniczeniu
gbn
źródło
+1 - Zgadzam się (patrz moja odpowiedź), że przykładowe indeksy w OP są bezwartościowe dla zapytania!
JNK
Świetny! jeszcze jedno, co decyduje o kolejności KeyColList i NonKeyColList. Czy możesz wyjaśnić na podstawie mojego przykładu? Załóżmy, że teraz moje zapytanie to WYBIERZ Identyfikator pracownika, ID działu, Nazwisko od pracownika GDZIE DZIAŁU = 5, ID państwa = 4 Jak powinien być teraz indeks?
@Rocky - NonKeyColListkolejność nie ma znaczenia. KeyColListkolejność powinna być zgodna z częstotliwością, jakiej oczekuje się od nich w zapytaniach. Zobacz moje uwagi do mojej odpowiedzi poniżej, ale to jak Last Name, First Name, Middile Initialw książce telefonicznej. Potrzebujesz pierwszego pola, aby znaleźć drugie pole.
JNK
@gbn Czy naprawdę wymagamy identyfikatora pracownika na liście uwzględnień? Ponieważ jeśli mamy indeks klastrowy w kolumnie EmployeeID, a jeśli utworzymy indeks nieklastrowany w kolumnie DeptId, to indeks nieklastrowany ma już odwołanie do klucza klastrowania, który jest zawarty w strukturze indeksu nieklastrowanego, w tym klucz klastrowania na liście INCLUDE nie ” dodać żadnych korzyści.
Viswanathan Iyer,
1
@ViswanathanIyer nie zostanie jednak dodany dwukrotnie do faktycznego miejsca na dysku: SQL Server to wykrywa. Więc to nie jest potrzebne, ale czyni to jaśniejszym. Jednak nie wiemy o żadnym indeksie klastrowym w pytaniu, więc bezpieczniej jest założyć brak.
gbn
19

JNK i gbn dały świetne odpowiedzi, ale warto również wziąć pod uwagę duży obraz - nie skupiając się tylko na jednym zapytaniu. Chociaż to konkretne zapytanie może skorzystać z indeksu (nr 1):

Employee(DepartmentID) INCLUDE (Lastname, EmployeeID)

Ten indeks w ogóle nie pomaga, jeśli zapytanie zmienia się nieznacznie, na przykład:

SELECT EmployeeID, DepartmentID, LastName
FROM Employee
WHERE DepartmentID = 5 AND LastName = 'Smith'

Wymagałoby to indeksu (# 2):

Employee(DepartmentID, LastName) INCLUDE (EmployeeID)

Wyobraź sobie, że miałeś 1000 pracowników w dziale 5. Korzystając z indeksu nr 1, aby znaleźć wszystkich Smithów, musisz przeszukać wszystkie 1000 wierszy w dziale 5, ponieważ zawarte kolumny nie są częścią klucza. Korzystając z indeksu # 2, możesz szukać bezpośrednio w dziale 5, LastName Smith.

Indeks nr 2 jest zatem bardziej przydatny w obsłudze szerszego zakresu zapytań - ale kosztem jest bardziej rozdęty klucz indeksu, który zwiększy strony nie-liściowe indeksu. Każdy system będzie inny, więc nie ma tu żadnej praktycznej zasady.


Na marginesie warto zauważyć, że jeśli identyfikator pracownika był kluczem do klastrowania dla tej tabeli - zakładając indeks klastrowany - to nie musisz uwzględniać identyfikatora pracownika - jest on obecny we wszystkich indeksach nieklastrowanych, co oznacza, że ​​indeks nr 2 mógłby po prostu być

Employee(DepartmentID, LastName)

źródło
2
+1, aby uzyskać więcej przydatnych informacji. W ostatnim punkcie przetestowałem to i jawne użycie Identyfikatora pracownika w INCLUDE jest faktycznie ignorowane (na podstawie wielkości indeksu), jeśli Identyfikator pracownika jest indeksem klastrowanym. Myślę, że jest to bardziej oczywiste i nie ma miejsca na minus.
gbn
1
Absolutnie się zgadzam - zawsze lepiej jest wyrażać się wyraźnie, zwłaszcza jeśli nic nie kosztuje!
1
Na wszelki wypadek ... Mam na myśli, że przetestowałem klastrowany klucz w INCLUDE (nie wyraźnie EmployeeID) i nie dodaje spacji. W kluczowych kolumnach tak.
gbn
@gbn Tak, klucz klastra musi znajdować się tylko na poziomie liścia indeksu, czyli tam, gdzie znajdują się kolumny INCLUDE. Przeniesienie go do klucza indeksu oznaczałoby, że istniałby on również na stronach innych niż liście. Spowodowałoby to trochę rozdęcia, ale nie straszną ilość (na stronach poziomu pośredniego dodawalibyśmy kolejne 4 bajty na stronę poziomu liścia, zakładając liczbę całkowitą).
To świetna odpowiedź, która obejmuje niektóre efekty opisane w tym artykule: sqlperformance.com/2014/07/sql-indexes/... Jeśli Twoje zapytanie ulegnie zmianie, zmień również wymagania swoich indeksów. Odpowiedź Jima może być lepsza, ale lepiej jest z odpowiedzią @gbn.
John aka hot2use,
7

Nie jestem pewien, skąd masz ten pierwszy. Dla mnie do tego zapytania użyłbym:

CREATE NONCLUSTERED INDEX NC_EmpDep 
  ON Employee(DepartmentID)
  INCLUDE (EmployeeID, Lastname)

Nie ma „twardej i szybkiej reguły” dla prawie wszystkiego w SQL.

Ale, na przykład, jedynym polem, którego będzie używał indeks, jest DepartmentIDto, że znajduje się w WHEREklauzuli.

Inne pola muszą być łatwo dostępne stamtąd. Wybierasz na podstawie DepartmentIDwtedy INCLUDEma te pola w węźle liścia indeksu.

Nie chcesz używać innych przykładów, ponieważ nie będą one działać dla tego indeksu.

Pomyśl o indeksie jak o książce telefonicznej. Większość książek telefonicznych jest uporządkowana według nazwiska, imienia i drugiej litery. Jeśli znasz czyjeś imię, ale nie nazwisko, książka telefoniczna nic ci nie da, ponieważ nie możesz wyszukiwać imienia na podstawie kolejności indeksu książki telefonicznej.

Te INCLUDEpola są jak numer telefonu, adres itp inne informacje dla każdego wpisu w książce.

EDYTOWAĆ:

Aby wyjaśnić, dlaczego nie używać:

CREATE NONCLUSTERED INDEX NC_EmpDep 
          ON Employee( EmployeeID, LastName)
INCLUDE (DepartmentID)

Indeks ten jest przydatna tylko jeśli masz albo EmployeeIDczy OBA EmployeeID oraz LastNamew WHEREklauzuli. To w zasadzie OPPOSITE tego, czego potrzebujesz do tego zapytania.

JNK
źródło
@ajbeaven to prawda, dlatego komentarz, który wstawiłem w edycji, mówi, że potrzebujesz EITHER pracownika lub obu kolumn.
JNK
durr sorry misread :(
ajbeaven
0

Wydaje mi się, że nadal możesz używać indeksu (identyfikator_użytkownika, identyfikator_działu), ale w frazie „musisz” wstawić wiersz „fikcyjny”, na przykład: „identyfikator_użytkownika = identyfikator_użytkownika”

  • posiadający indeks na (identyfikator_użytkownika, identyfikator_oddziału),
  • konieczność wyszukiwania / ograniczania tylko dla ID_ departamentu
  • wiedząc, że nie użyje indeksu, ponieważ zła kolejność (lub rzeczy się zmieniły, a następująca „sztuczka” nie jest już potrzebna. Jestem „stara”?) .
  • Używać „starej” sztuczki?

    wybierz * z Employee emp
    gdzie emp.employee_id = emp.employee_id
    i emp.department_id = 5

(Więc nie skupiam się na włączeniu tutaj Lastname, ale na tak / lub nieużywanie klucza.)

Z poważaniem,

Miguell

Miguel Leeuwe
źródło
2
Nie, to jest bezużyteczne i nieefektywne.
ypercubeᵀᴹ
W szczególności nadal będzie musiał być skanowany indeks w celu przeszukania każdego identyfikatora pracownika w celu znalezienia wszystkich instancji działu id_id 5. Jeśli jest 1000 pracowników i 5 działów, SQL musi przejrzeć wszystkich 1000 pracowników, aby znaleźć wszystkie wiersze dla określonego działu.
Mark Sowul
Teraz rozważ przeciwny przypadek (indeks znajduje się na id_działu, id_użytkownika). Oczywiście łatwo jest teraz znaleźć konkretny dział, ale należy również pamiętać, że aby znaleźć konkretnego pracownika, SQL musi tylko przejrzeć 5 działów, aby znaleźć wszystkie wiersze dla konkretnego pracownika.
Mark Sowul