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.
Odpowiedzi:
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
PersonId
oznacza, że wiersze będą fizycznie sortowane wedługPersonId
w 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ć
CourtOrderId
kolumny klucza zastępczego (twojej ) jako klucza podstawowego, ale zamiast tego użyj złożonego klucza podstawowegoPersonId
i kilku innych jednoznacznie identyfikujących się kolumn lub zestawu kolumn. Jeśli jednak nie jest to możliwe (lub niepraktyczne), włącz indeks klastrowyCourtOrderId
.źródło
PersonId
. Jest on logicznie posortowany wedługPersonId
, każda rozbieżność między porządkiem logicznym i fizycznym jest stopniem fragmentacji logicznej.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!
źródło
Niektórzy autorzy sugerują nie „marnować” THE
CI
naidentity
kolumnie, 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
Twoja
CourtOrderID
kolumna się spotyka2
. TwojePersonId
spotkania1
i3
. Ponieważ większość wierszy i tak kończy sięuniqueifier
dodaniem, równie dobrze możesz po prostu zadeklarować je jako unikalne i użyć,PersonId,CourtOrderID
ponieważ 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,CourtOrderID
jako 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.źródło
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.
źródło
Niektóre bazy danych z nieprzyjemnymi selekcjami, łączenia w procedurze składowanej - jedyną różnicą jest indeks
INDEKSY - klastrowany vs nieklastrowy
źródło