Czy indeksy klastrowe muszą być unikalne?

84

Co się stanie, jeśli indeks klastrowy nie jest unikalny? Czy może to prowadzić do złej wydajności, ponieważ wstawione wiersze wpływają na pewnego rodzaju „przepełnioną” stronę?

Czy jest „stworzony” jako wyjątkowy, a jeśli tak, to w jaki sposób? Jaki jest najlepszy sposób, aby uczynić go wyjątkowym?

Pytam, ponieważ obecnie używam indeksu klastrowego do podzielenia mojej tabeli na części logiczne, ale wydajność jest taka sobie, a ostatnio otrzymałem poradę, aby moje indeksy klastrowe były unikalne. Chciałbym uzyskać drugą opinię na ten temat.

Dzięki!

mało zielony
źródło

Odpowiedzi:

92

Nie muszą być wyjątkowe, ale z pewnością jest to zalecane.
Nie spotkałem jeszcze scenariusza, w którym chciałbym utworzyć CI w nieunikalnej kolumnie.

Co się stanie, jeśli utworzysz CI w nieunikalnej kolumnie

Jeśli indeks klastrowy nie jest indeksem unikatowym, SQL Server sprawia, że ​​wszystkie zduplikowane klucze są unikalne, dodając wewnętrznie wygenerowaną wartość zwaną unikatnikiem

Czy to prowadzi do złej wydajności?

Dodanie unikalnego identyfikatora z pewnością zwiększa obciążenie związane z obliczaniem i przechowywaniem.
To, czy ten narzut będzie zauważalny, zależy od kilku czynników.

  • Ile danych zawiera tabela.
  • Jaka jest stawka wkładek.
  • Jak często jest używany CI w selekcji (kiedy nie istnieją indeksy pokrywające, prawie zawsze).

Edycja,
jak wskazał Remus w komentarzach, istnieją przypadki użycia, w których stworzenie nieunikalnego CI byłoby rozsądnym wyborem. Fakt, że nie spotkałem się z żadnym z tych scenariuszy, po prostu pokazuje mój brak ekspozycji lub kompetencji (wybierz swój wybór).

Lieven Keersmaekers
źródło
31
+1, ponieważ wszystko, co mówisz, jest poprawne, ale chciałem tylko dodać: nieunikalne CI są dość powszechne, gdy przeważającym wzorcem dostępu jest skanowanie zakresu w określonej (nieunikalnej) kolumnie.
Remus Rusanu
@Remus Ruşanu: I został myślenie o dodanie zastrzeżenia do mojego oświadczenia scenariusza podobnego , ale to nic nie znaczy . Dziękujemy za wskazanie scenariusza, w którym może się to przydać.
Lieven Keersmaekers
4
@Remus: masz na myśli sytuację niszową, w której masz nieunikalną kolumnę, taką jak „Departmentid”, w której wpisujesz coś w rodzaju „DepartmentId BETWEEN 1 i 100”? edytuj ah, rozumiem, co masz na myśli, tak, kolumna daty w tabeli logowania też jest dobrym przykładem.
mały zielony
Hej, mam tabelę strumienia zdarzeń, w której istnieje wiele wierszy z tym samym „AggregateId”, który jest kolumną typu GUID. Jedyne zapytania wykonywane na tabeli to pobranie wszystkich zdarzeń dla danego AggregateId. Zastanawiam się, czy powinien to być indeks klastrowy czy nieklastrowy?
Shayan C
@ShayanC - Jeśli wydajność pobierania jest Twoim głównym celem, ustawiłbym jako CI prawdopodobnie oszczędzanie na IO podczas pobierania wszystkich wierszy dla danego identyfikatora. Podobnie jak w przypadku wszystkich scenariuszy wydajnościowych, jedynym pewnym sposobem jest pomiar.
Lieven Keersmaekers
32

Lubię sprawdzić, co na ten temat ma do powiedzenia Kimberly Tripp The Queen of Indexing:

Zacznę od mojej rekomendacji klucza klastrowego - z kilku powodów. Po pierwsze, jest to łatwa decyzja, a po drugie, wczesne podjęcie takiej decyzji pomaga aktywnie zapobiegać niektórym typom fragmentacji. Jeśli możesz zapobiec pewnym typom fragmentacji tabeli bazowej, możesz zminimalizować niektóre czynności konserwacyjne (z których niektóre w SQL Server 2000 ORAZ mniejsze w SQL Server 2005) wymagają, aby tabela była w trybie offline. OK, przejdę do odbudowy później .....

Zacznijmy od kluczowych rzeczy, których szukam w kluczu klastrowym:

* Unique
* Narrow
* Static

Dlaczego wyjątkowy? Klucz klastra powinien być unikalny, ponieważ klucz klastrowania (jeśli taki istnieje) jest używany jako klucz wyszukiwania ze wszystkich indeksów nieklastrowanych. Weźmy na przykład indeks na końcu książki - jeśli chcesz znaleźć dane, na które wskazuje wpis indeksu - ten wpis (wpis indeksu) musi być unikalny, w przeciwnym razie który wpis indeksu byłby tym, którego szukasz ? Więc kiedy tworzysz indeks klastrowy - musi być unikalny. Ale SQL Server nie wymaga, aby klucz klastrowania był tworzony w unikatowej kolumnie. Możesz go utworzyć w dowolnej kolumnie (kolumnach). Wewnętrznie, jeśli klucz klastrowania nie jest unikalny, SQL Server „ujednolici” go, dodając 4-bajtową liczbę całkowitą do danych. Więc jeśli indeks klastrowy jest tworzony na czymś, co nie jest unikalne, to nie tylko występuje dodatkowe obciążenie związane z tworzeniem indeksu, ale także marnowane miejsce na dysku,

Źródło: Coraz większa debata na temat klastrów - znowu!

marc_s
źródło
Pytanie jednak, Queen zaleca nowy identyfikator w celu ujednolicenia danych, ale SQL Server generuje własny unikat, jeśli go nie określisz. Czy w takim razie jest jeszcze jakiś powód, aby dodać własny identyfikator sekwencyjny?
mały zielony
2
@littlegreen: mówi, że jeśli nalegasz na używanie identyfikatorów GUID (które są naprawdę złe do użycia w indeksie klastrowym), to przynajmniej użyj, newsequentialid()aby uzyskać prawie sekwencyjny identyfikator GUID. Ale tak: jeżeli ty dodaj swój własny, unikalny identyfikator (I zawsze wolą INT IDENTITY), to trzeba tę wartość pod ręką i można go używać (np ustanowienie relacji FK). Unikatowe elementy dodane przez SQL Server są dla Ciebie niewidoczne, a zatem są tylko narzutem, którego nie możesz wykorzystać.
marc_s
Widzę. Byłby to argument przemawiający za indeksem klastrowym (CompanyID, DepartmentID, ID INT IDENTITY) zamiast tylko pierwszych dwóch. Dzięki!
mały zielony
1
@littlegreen: jeszcze lepiej - utwórz indeks klastrowy tylko na (ID INT IDENTITY) i umieść inne pola - w razie potrzeby - w oddzielnym indeksie nieklastrowym. Indeks klastrowy powinien być tak mały, jak to tylko możliwe - w końcu kolumny indeksów klastrowych są dodawane do każdego wpisu każdego indeksu nieklastrowego w tej tabeli - więc nie marnuj swoich bajtów na szerokie klastrowe indeks!
marc_s
1
Tak, ale wtedy tracę korzyści wynikające z grupowania wszystkich danych mojego działu i możliwości jednoczesnego wstawiania / usuwania / pobierania całego działu. Moje dane zostaną rozproszone, a wstawianie / usuwanie całych działów lub nawet całych firm będzie działać wolno. Moje zapytania są zawsze uruchamiane tylko w jednej firmie na raz i często cały zbiór danych wymaga aktualizacji.
mały zielony
9

Czy indeksy klastrowe muszą być unikalne?

Nie robią i są chwile, kiedy lepiej jest, jeśli nie są.

Rozważ tabelę z pół-losowym, unikalnym identyfikatorem pracownika i identyfikatorem działu dla każdego pracownika: jeśli Twoja instrukcja select jest

SELECT * FROM EmployeeTable WHERE DepartmentId=%DepartmentValue%

wtedy najlepiej pod względem wydajności jest, jeśli DepartmentIdjest to indeks klastrowy, mimo że (a zwłaszcza dlatego, że) nie jest indeksem unikatowym (najlepiej pod względem wydajności, ponieważ zapewnia, że ​​wszystkie rekordy w ramach danego DepartmentId są zgrupowane).


Czy masz jakieś referencje?

Na przykład istnieją Wytyczne dotyczące projektowania indeksów klastrowych , które mówią:

Z kilkoma wyjątkami każda tabela powinna mieć indeks klastrowy zdefiniowany w kolumnie lub kolumnach, które oferują następujące opcje:

  • Może być używany do często używanych zapytań.
  • Zapewniają wysoki stopień niepowtarzalności.
  • Może być używany w zapytaniach o zakres.

Rozumiem na przykład, że „wysoki stopień unikalności” jest taki, że wybranie „Kraj” jako indeksu klastrowego nie jest dobre, jeśli większość zapytań chce wybrać rekordy w danym mieście.

ChrisW
źródło
Tak właśnie myślałem do tej pory, ale otrzymałem też dokładnie odwrotną radę, więc zastanawiam się, co jest prawdą. Czy masz jakieś referencje?
mały zielony
@littlegreen Zmodyfikowałem swoją odpowiedź, aby spróbować odpowiedzieć na Twoje pytanie.
ChrisW,
Dzięki. Dobra, rozumiem twój punkt widzenia. Ale jeśli regularnie wstawiasz od razu cały kraj, grupowany indeks dla (kraj, miasto) wydaje mi się uciążliwy, ponieważ wymaga sortowania danych. Z drugiej strony sortowanie przed wstawieniem nie byłoby tak wielkim problemem ...
mały zielony
3
Z pewnością w twoim przykładzie preferowany byłby unikalny indeks klastrowy {DepartmentID, EmployeeID}? Dlaczego system miałby tworzyć unikatowy identyfikator, skoro istniejące pole zapewniałoby unikalność przy mniejszym narzutie (prawdopodobnie czterobajtowe INT) i może pozwolić na uruchomienie kilku dodatkowych zapytań w samym indeksie?