Podczas nauki do egzaminu 70-433 zauważyłem, że możesz utworzyć indeks obejmujący na jeden z dwóch poniższych sposobów.
CREATE INDEX idx1 ON MyTable (Col1, Col2, Col3)
- LUB -
CREATE INDEX idx1 ON MyTable (Col1) INCLUDE (Col2, Col3)
Klauzula INCLUDE jest dla mnie nowa. Dlaczego miałbyś go używać i jakie wskazówki sugerowałbyś przy ustalaniu, czy utworzyć indeks obejmujący z klauzulą INCLUDE, czy bez?
SELECT
a dla niektórych nie? \Można użyć INCLUDE, aby dodać jedną lub więcej kolumn do poziomu liścia indeksu nieklastrowanego, jeśli dzięki temu można „zakryć” swoje zapytania.
Wyobraź sobie, że musisz zapytać o identyfikator pracownika, identyfikator działu i nazwisko.
Jeśli akurat masz indeks nieklastrowany na (EmployeeID, DepartmentID), po znalezieniu pracowników dla danego działu musisz teraz wykonać „przeglądanie zakładek”, aby uzyskać rzeczywisty pełny rekord pracownika, aby uzyskać kolumnę nazwiska . To może stać się dość drogie pod względem wydajności, jeśli znajdziesz wielu pracowników.
Jeśli włączyłeś to nazwisko do swojego indeksu:
wtedy wszystkie potrzebne informacje są dostępne na poziomie liści indeksu nieklastrowanego. Wystarczy poszukać w indeksie nieklastrowanym i znaleźć pracowników dla danego działu, masz wszystkie niezbędne informacje, a wyszukiwanie zakładek dla każdego pracownika w indeksie nie jest już konieczne -> oszczędzasz dużo czasu.
Oczywiście nie można uwzględnić każdej kolumny w każdym indeksie nieklastrowanym - ale jeśli masz zapytania, w których brakuje tylko jednej lub dwóch kolumn do „pokrycia” (i które często się przyzwyczajają), bardzo pomocne może być WŁĄCZENIE ich w odpowiedni indeks nieklastrowany.
źródło
JOIN
kluczach w zapytaniu, aINCLUDE
muszą to być dane, które pobierasz, ale nie sortujesz.W tej dyskusji brakuje ważnego punktu: nie chodzi o to, czy „kolumny niekluczowe” lepiej uwzględnić jako kolumny indeksowe lub jako kolumny włączone .
Pytanie brzmi, jak drogie jest użycie mechanizmu włączania do uwzględnienia kolumn, które tak naprawdę nie są potrzebne w indeksie ? (zazwyczaj nie jest częścią klauzul gdzie, ale często jest włączana do selekcji). Zatem twoim dylematem jest zawsze:
Gdzie: ID1, ID2 ... IDN są często stosowane w kolumnach ograniczeń i col1, col2 ... Cöln kolumny są często wybrane, ale zwykle nie stosuje się w ograniczeniach
(Opcja włączenia wszystkich tych kolumn jako części klawisza indeksu jest po prostu zawsze głupia (chyba że są one również używane w ograniczeniach) - ponieważ utrzymanie zawsze byłoby droższe, ponieważ indeks musi być aktualizowany i sortowany, nawet gdy „klucze” nie uległy zmianie).
Więc użyj opcji 1 lub 2?
Odpowiedź: Jeśli tabela jest rzadko aktualizowana - głównie wstawiony / usunięty z - to jest stosunkowo niedrogie w użyciu include-mechanizm zawierać kilka „gorących kolumny” (które są często używane w wybiera - ale nie często używany w sprawie ograniczeń), ponieważ wstawianie / usuwanie wymaga i tak aktualizacji / sortowania indeksu, a zatem niewielkie dodatkowe obciążenie związane jest z przechowywaniem kilku dodatkowych kolumn podczas już aktualizacji indeksu. Narzut to dodatkowa pamięć i procesor używane do przechowywania nadmiarowych informacji w indeksie.
Jeśli kolumny, które chcesz dodać jako dołączone, są często aktualizowane (bez aktualizacji klucza indeksu -kolumny) - lub - jeśli jest ich tak wiele, że indeks zbliża się do kopii tabeli - skorzystaj z opcji 1 Sugerowałbym! Także jeśli dodanie niektórych kolumn uwzględnienia nie spowoduje różnicy w wydajności - możesz pominąć pomysł ich dodania :) Sprawdź, czy są one przydatne!
Ważna może być również średnia liczba wierszy dla tych samych wartości w kluczach (id1, id2 ... idN).
Zauważ, że jeśli kolumna - która jest dodawana jako dołączona kolumna indeksu - jest używana w ograniczeniu : Tak długo, jak indeks może być używany jako taki (w oparciu o ograniczenie przeciwko kluczowi indeksu -kolumny) - wtedy SQL Server jest zgodny ograniczenie kolumny względem indeksu (wartości typu liść-węzeł) zamiast omijać kosztowną drogę wokół samej tabeli.
źródło
Podstawowe kolumny indeksu są sortowane, ale uwzględnione kolumny nie są sortowane. Oszczędza to zasoby w utrzymywaniu indeksu, a jednocześnie umożliwia podawanie danych w dołączonych kolumnach na potrzeby zapytania. Tak więc, jeśli chcesz uwzględnić zapytania, możesz umieścić kryteria wyszukiwania, aby zlokalizować wiersze w posortowanych kolumnach indeksu, a następnie „uwzględnić” dodatkowe, nieposortowane kolumny z danymi nieprzeszukiwanymi. To zdecydowanie pomaga w zmniejszeniu ilości sortowania i fragmentacji w utrzymywaniu indeksu.
źródło
Powody, dla których (w tym dane na poziomie liści indeksu) zostały dobrze wyjaśnione. Powodem, dla którego podajesz dwa drżenia na ten temat, jest to, że po uruchomieniu zapytania, jeśli nie masz dodatkowych kolumn (nowa funkcja w SQL 2005), SQL Server musi przejść do indeksu klastrowego, aby uzyskać dodatkowe kolumny co zajmuje więcej czasu i zwiększa obciążenie usługi SQL Server, dysków i pamięci (konkretnie pamięci podręcznej bufora), gdy nowe strony danych są ładowane do pamięci, potencjalnie wypychając inne, często potrzebne dane, z pamięci podręcznej bufora.
źródło
Dodatkowym zagadnieniem, którego nie widziałem w odpowiedziach już podanych, jest to, że dołączone kolumny mogą należeć do typów danych, które nie są dozwolone jako kolumny klucza indeksu, takie jak varchar (max).
Pozwala to na włączenie takich kolumn do indeksu obejmującego. Niedawno musiałem to zrobić, aby dostarczyć zapytanie generowane przez nHibernate, które zawierało wiele kolumn w SELECT, z przydatnym indeksem.
źródło
Jednym z powodów, aby preferować
INCLUDE
kolumny klucza, jeśli nie potrzebujesz tej kolumny w kluczu, jest dokumentacja. To sprawia, że ewolucja indeksów będzie znacznie łatwiejsza w przyszłości.Biorąc pod uwagę twój przykład:
Ten indeks jest najlepszy, jeśli zapytanie wygląda następująco:
Oczywiście nie powinieneś wstawiać kolumn,
INCLUDE
jeśli możesz uzyskać dodatkową korzyść z posiadania ich w kluczowej części. Oba poniższe zapytania faktycznie wolącol2
kolumnę w kluczu indeksu.Załóżmy, że tak nie jest i mamy to
col2
wINCLUDE
klauzuli, ponieważ po prostu nie ma korzyści z posiadania go w części drzewa indeksu.Kilka lat do przodu.
Musisz dostroić to zapytanie:
Aby zoptymalizować to zapytanie, świetny byłby następujący indeks:
Jeśli sprawdzisz, jakie indeksy masz już w tej tabeli, twój poprzedni indeks może nadal tam być:
Teraz wiesz o tym
Col2
iCol3
nie są częścią drzewa indeksów, a zatem nie są używane do zawężania zakresu indeksu odczytu ani do porządkowania wierszy. Można raczej bezpiecznie dodaćanother_column
na końcu kluczowej części indeksu (pocol1
). Ryzyko zniszczenia czegokolwiek jest niewielkie:Indeks ten będzie większy, co nadal wiąże się z pewnym ryzykiem, ale ogólnie lepiej jest rozszerzyć istniejące indeksy niż wprowadzać nowe.
Jeśli miałbyś indeks bez
INCLUDE
, nie wiedziałbyś, jakie zapytania przerwałbyś, dodającanother_col
zaraz potemCol1
.Co się stanie, jeśli dodasz
another_col
pomiędzyCol1
iCol2
? Czy ucierpią inne zapytania?Istnieją inne „zalety” w
INCLUDE
porównaniu z kluczowymi kolumnami, jeśli dodasz te kolumny tylko po to, aby uniknąć pobierania ich z tabeli . Uważam jednak, że najważniejszy jest aspekt dokumentacji.Odpowiedzieć na Twoje pytanie:
Jeśli dodasz kolumnę do indeksu wyłącznie w celu udostępnienia tej kolumny w indeksie bez odwiedzania tabeli, umieść ją w
INCLUDE
klauzuli.Jeśli dodanie kolumny do klucza indeksu przynosi dodatkowe korzyści (np. Dla
order by
lub ponieważ może zawęzić zakres odczytu indeksu), dodaj ją do klucza.Dłuższą dyskusję na ten temat możesz przeczytać tutaj:
https://use-the-index-luke.com/blog/2019-04/include-columns-in-btree-indexes
źródło
W definicji indeksu istnieje ograniczenie całkowitego rozmiaru wszystkich kolumn. Mimo to nigdy nie musiałem tworzyć tak szerokiego indeksu. Dla mnie większą zaletą jest to, że możesz pokryć więcej zapytań za pomocą jednego indeksu zawierającego kolumny, ponieważ nie trzeba ich definiować w określonej kolejności. Pomyśl o tym jak o indeksie w ramach indeksu. Przykładem może być StoreID (gdzie StoreID ma niską selektywność, co oznacza, że każdy sklep jest powiązany z wieloma klientami), a następnie dane demograficzne klientów (LastName, FirstName, DOB): Jeśli wstawisz te kolumny w tej kolejności (StoreID, LastName , FirstName, DOB), możesz tylko efektywnie wyszukiwać klientów, dla których znasz StoreID i LastName.
Z drugiej strony, zdefiniowanie indeksu na StoreID i uwzględnienie kolumn LastName, FirstName, DOB pozwoliłoby w zasadzie na wykonanie dwóch predykatów wyszukiwania na StoreID, a następnie wyszukanie predykatu na dowolnej z zawartych kolumn. Pozwoliłoby to objąć wszystkie możliwe permutacje wyszukiwania, o ile zaczynają się od StoreID.
źródło