Klastrowany a nieklastrowy

98

Moja znajomość SQL na niższym poziomie (Server 2008) jest ograniczona i obecnie jest to wyzwanie dla naszych administratorów baz danych. Pozwól mi wyjaśnić (wspomniałem o oczywistych stwierdzeniach w nadziei, że mam rację, ale jeśli widzisz coś nie tak, powiedz mi) scenariusz:

Mamy stół, na którym znajdują się „nakazy sądowe” dla ludzi. Kiedy tworzyłem tabelę (Name: CourtOrder), utworzyłem ją w następujący sposób:

CREATE TABLE dbo.CourtOrder
(
  CourtOrderID INT NOT NULL IDENTITY(1,1), (Primary Key)
  PersonId INT NOT NULL,
  + around 20 other fields of different types.
)

Następnie zastosowałem indeks nieklastrowy do klucza podstawowego (w celu zwiększenia wydajności). Powodem jest to, że jest to unikalne pole (klucz podstawowy) i powinno być indeksowane, głównie w celu selekcji, ponieważ częstoSelect from table where primary key = ...

Następnie zastosowałem indeks CLUSTERED na PersonId. Powodem było fizyczne grupowanie zamówień dla konkretnej osoby, ponieważ zdecydowana większość pracy to uzyskiwanie zamówień na osobę. Więc,select from mytable where personId = ...

Zostałem w tym teraz wciągnięty. Powiedziano mi, że powinniśmy umieścić indeks klastrowy na kluczu podstawowym, a normalny indeks na personId. Wydaje mi się to bardzo dziwne. Po pierwsze, dlaczego miałbyś umieścić indeks klastrowy w unikalnej kolumnie? co to jest klaster? Z pewnością to strata indeksu klastrowego? Myślałem, że w unikalnej kolumnie zostanie użyty normalny indeks. Ponadto grupowanie indeksu oznaczałoby, że nie możemy grupować różnych kolumn (po jednej na tabelę, prawda?).

Powodem, dla którego powiedziano mi, że popełniłem błąd, jest to, że uważają, że umieszczenie grupowanego indeksu na PersonId spowolniłoby wstawianie. W przypadku 5% wzrostu szybkości wybranego elementu uzyskalibyśmy 95% spadek szybkości wstawiania i aktualizacji. Czy to jest poprawne i ważne?

Mówią, że ponieważ tworzymy grupę personId, SQL Server musi zmienić kolejność danych za każdym razem, gdy wstawiamy lub zmieniamy PersonId.

Więc zapytałem, dlaczego SQL miałby mieć pojęcie INDEKSU KLASTEROWEGO, skoro jest tak wolny? Czy jest tak wolno, jak mówią? Jak należy skonfigurować indeksy, aby uzyskać optymalną wydajność? Myślałem, że SELECT jest używany częściej niż INSERT ... ale mówią, że mamy problemy z blokowaniem na INSERTS ...

Mam nadzieję, że ktoś może mi pomóc.

Craig
źródło

Odpowiedzi:

117

Różnica między indeksem klastrowym a indeksem nieklastrowym polega na tym, że indeks klastrowy określa fizyczną kolejność wierszy w bazie danych . Innymi słowy, zastosowanie indeksu klastrowego do PersonIdoznacza, że ​​wiersze będą fizycznie sortowane według PersonIdw tabeli, umożliwiając przeszukiwanie indeksu bezpośrednio do wiersza (zamiast indeksu nieklastrowego, który kierowałby cię do wiersza lokalizacja, dodając dodatkowy krok).

To powiedziawszy, jest niezwykłe, że klucz podstawowy nie jest indeksem klastrowym, ale nie jest to niespotykane. Problem z twoim scenariuszem jest w rzeczywistości przeciwieństwem tego, co zakładasz: chcesz mieć unikalne wartości w indeksie klastrowym, a nie duplikaty. Ponieważ indeks klastrowany określa fizyczną kolejność wiersza, jeśli indeks znajduje się w nieunikalnej kolumnie, serwer musi dodać wartość tła do wierszy, które mają zduplikowaną wartość klucza (w twoim przypadku wszystkie wiersze z taką samą PersonId), aby połączona wartość (klucz + wartość tła) była niepowtarzalna.

Jedyne, co sugerowałbym, to nie używać CourtOrderIdkolumny klucza zastępczego (twojej ) jako klucza podstawowego, ale zamiast tego użyj złożonego klucza podstawowego PersonIdi kilku innych jednoznacznie identyfikujących się kolumn lub zestawu kolumn. Jeśli jednak nie jest to możliwe (lub niepraktyczne), włącz indeks klastrowy CourtOrderId.

Adam Robinson
źródło
Dzięki Adam. Kiedy więc indeks klastrowy byłby przydatny? Pomyślałem, że korzyścią dla indeksu klastrowego było grupowanie danych, na przykład, gdy większość zapytań dotyczy identyfikatora PersonID ... więc dane będą grupowane.
Craig,
3
To jest nie fizycznie posortowane wg PersonId. Jest on logicznie posortowany według PersonId, każda rozbieżność między porządkiem logicznym i fizycznym jest stopniem fragmentacji logicznej.
Martin Smith,
1
@cdotlister Zaletą indeksu jest sortowanie danych, a nie ich grupowanie (co powodowało zduplikowane dane w indeksie). Chociaż rozróżnienie to może wydawać się semantyczne, w przypadku indeksów grupowanych tak nie jest. Jeśli to możliwe, indeks klastrowy powinien znajdować się na czymś, co jednoznacznie identyfikuje wiersz i (najlepiej) jest również najczęściej używaną kolumną lub zestawem kolumn. Dlatego zwykle znajduje się na kluczu podstawowym.
Adam Robinson,
1
@CyberSluethOmega: Nie wiem; Twoje pytanie nie zawiera wystarczających informacji, abym mógł podjąć decyzję. Czy chciałbym, aby indeks klastrowy obejmował zestaw kolumn, w których wiersze byłyby często dodawane lub usuwane poza końcem tabeli ? Nie. Ale nie jestem pewien, dlaczego o to pytasz ani dlaczego głosujesz przeciw.
Adam Robinson
1
@CyberSluethOmega: Internet może sprawiać, że komentarze brzmią defensywnie lub chłodno, jeśli nie są w ten sposób zamierzone. Twierdziliście, że powiedziałem, iż nie znam żadnych okoliczności, w których uczynienie indeksu klastrowego czymś innym niż klucz podstawowy, podczas gdy w rzeczywistości nic takiego nie powiedziałem. W rzeczywistości, co powiedziałem było „to jest niezwykłe ..., ale nie niespotykane”, co oznacza, że nie wiedzą o przypadkach, kiedy to nastąpi.
Adam Robinson
14

W żadnym wypadku nie jestem ekspertem od SQL ... więc potraktuj to raczej jako widok programisty niż widok DBA.

Wstawienia w klastrowanych (uporządkowanych fizycznie) indeksach, które nie są w kolejności sekwencyjnej, powodują dodatkową pracę w przypadku wstawiania / aktualizacji. Ponadto, jeśli masz wiele wstawek dzieje się jednocześnie i wszystkie pojawiają się w tym samym miejscu, kończy się to sporem. Twoja konkretna wydajność różni się w zależności od danych i sposobu, w jaki uzyskujesz do nich dostęp. Ogólną zasadą jest zbudowanie indeksu klastrowego na najbardziej unikalnej wąskiej wartości w tabeli (zazwyczaj PK)

Zakładam, że Twój PersonId się nie zmieni, więc aktualizacje nie wchodzą tutaj w grę. Ale rozważ migawkę kilku wierszy z PersonId 1 2 3 3 4 5 6 7 8 8

Teraz wstaw 20 nowych wierszy dla PersonId 3. Najpierw, ponieważ nie jest to unikalny klucz, serwer dodaje dodatkowe bajty do twojej wartości (za kulisami), aby uczynić ją unikalną (co również dodaje dodatkową przestrzeń), a następnie lokalizację, w której te miejsca zamieszkania muszą zostać zmienione. Porównaj to z wstawianiem automatycznie zwiększającego się PK, w którym wstawianie następuje na końcu. Nietechniczne wyjaśnienie prawdopodobnie sprowadziłoby się do tego: jest mniej pracy `` tasowania liści '' do wykonania, jeśli naturalnie zwiększa się wyższe wartości na końcu tabeli, w porównaniu do zmiany położenia istniejących elementów w tym miejscu podczas wstawiania przedmiotów.

Teraz, jeśli masz problemy z wstawkami, prawdopodobnie wstawisz kilka takich samych (lub podobnych) wartości PersonId naraz, co powoduje tę dodatkową pracę w różnych miejscach w tabeli, a fragmentacja cię zabija. Wadą przejścia na PK, który jest skupiony w twoim przypadku, jest to, że jeśli masz dziś problemy z wstawianiem na PersonIds, które różnią się wartością rozłożoną w całej tabeli, jeśli zmienisz indeks klastrowy na PK i wszystkie wstawienia zostaną teraz wykonane w jednym lokalizacja, wtedy twój problem może się pogorszyć z powodu zwiększonej koncentracji rywalizacji. (Z drugiej strony, jeśli twoje dzisiejsze inserty nie są rozrzucone po całym, ale wszystkie są zwykle zgrupowane w podobnych obszarach, problem prawdopodobnie złagodzi się, zmieniając indeks klastrowy z PersonId na PK, ponieważ zminimalizujesz podział.)

Twoje problemy z wydajnością powinny być analizowane pod kątem Twojej wyjątkowej sytuacji i traktować tego typu odpowiedzi jako ogólne wskazówki. Najlepszym rozwiązaniem jest poleganie na DBA, który może dokładnie sprawdzić, gdzie leżą Twoje problemy. Wygląda na to, że masz problemy z rywalizacją o zasoby, które mogą wykraczać poza prostą modyfikację indeksu. Może to być objaw znacznie większego problemu. (Prawdopodobne problemy z projektem ... w przeciwnym razie ograniczenia zasobów.)

W każdym razie powodzenia!

Darian Miller
źródło
5

Niektórzy autorzy sugerują nie „marnować” THE CIna identitykolumnie, czy istnieje alternatywa, która będzie korzystać zapytań zasięgu.

Z Wytycznych dotyczących projektowania indeksów klastrowych MSDN należy wybrać klucz zgodnie z następującymi kryteriami

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

Twoja CourtOrderIDkolumna się spotyka 2. Twoje PersonIdspotkania 1i 3. Ponieważ większość wierszy i tak kończy się uniqueifierdodaniem, równie dobrze możesz po prostu zadeklarować je jako unikalne i użyć, PersonId,CourtOrderIDponieważ będzie to ta sama szerokość, ale będzie bardziej użyteczne, ponieważ klucz indeksu klastrowego jest dodawany do wszystkich NCI jako lokalizator wierszy, a to pozwoli aby uwzględnić więcej zapytań.

Głównym problemem związanym z używaniem PersonId,CourtOrderIDjako CI jest to, że prawdopodobnie nastąpi logiczna fragmentacja (a to szczególnie wpływa na zapytania o zakres, które próbujesz pomóc), więc będziesz musiał monitorować współczynnik wypełnienia i poziomy fragmentacji oraz częściej przeprowadzać konserwację indeksu.

Martin Smith
źródło
3

Jest to wyjaśnione w poniższym linku: https://msdn.microsoft.com/en-us/ms190457.aspx

Zgrupowane

  • Klastrowane indeksy sortują i przechowują wiersze danych w tabeli lub widoku na podstawie ich kluczowych wartości. To są kolumny zawarte w definicji indeksu. W tabeli może istnieć tylko jeden indeks klastrowy, ponieważ same wiersze danych można sortować tylko w jednym porządku.

  • Jedynym przypadkiem, w którym wiersze danych w tabeli są przechowywane w kolejności posortowanej, jest sytuacja, gdy tabela zawiera indeks klastrowy. Jeśli tabela ma indeks klastrowy, nazywana jest tabelą klastrowaną. Jeśli tabela nie ma indeksu klastrowego, jej wiersze danych są przechowywane w nieuporządkowanej strukturze zwanej stertą.

Nieklastrowany

  • Indeksy nieklastrowe mają strukturę oddzielną od wierszy danych. Indeks nieklastrowy c zachowuje wartości klucza indeksu nieklastrowego, a każdy wpis wartości klucza ma wskaźnik do wiersza danych, który zawiera wartość klucza .

  • Wskaźnik z wiersza indeksu w indeksie nieklastrowym do wiersza danych jest nazywany lokalizatorem wierszy. Struktura lokalizatora wierszy zależy od tego, czy strony danych są przechowywane w stercie, czy w tabeli klastrowanej. W przypadku sterty lokalizator wierszy jest wskaźnikiem do wiersza. W przypadku tabeli klastrowanej lokalizatorem wierszy jest klucz indeksu klastrowego.

  • Możesz dodać kolumny niebędące kluczem do poziomu liścia indeksu nieklastrowego, aby ominąć istniejące limity klucza indeksu, 900 bajtów i 16 kolumn klucza, i wykonywać w pełni objęte, indeksowane zapytania.

user2191454
źródło
-3

Niektóre bazy danych z nieprzyjemnymi selekcjami, łączenia w procedurze składowanej - jedyną różnicą jest indeks

INDEKSY - klastrowany vs nieklastrowy

  891 rows
  10 sec
  NONCLUSTERED 

  OR

  891 rows
  14 sec
  CLUSTERED
toLucky
źródło