Wybierając klucz podstawowy, zwykle wybierasz również klucz klastrowy. Tych dwoje często się myli, ale musisz zrozumieć różnicę.
Klucze podstawowe są logiczne biznesowe elementy. Klucz podstawowy jest używany przez aplikację do identyfikowania jednostki, a dyskusja na temat kluczy podstawowych dotyczy w dużej mierze użycia kluczy naturalnych lub klucza zastępczego. Linki są bardziej szczegółowe, ale podstawową ideą jest to, że naturalne klucze pochodzą z istniejącej właściwości encji, takiej jak ssn
lub phone number
, podczas gdy klucze zastępcze nie mają żadnego znaczenia w odniesieniu do jednostki biznesowej, np. id
lub rowid
i zazwyczaj są typu IDENTITY
lub jakiś rodzaj uuid. Osobiście uważam, że klucze zastępcze są lepsze od kluczy naturalnych, a wyborem powinny być zawsze wartości tożsamości tylko dla lokalnych aplikacji, przewodniki dla dowolnego rodzaju rozproszonych danych. Klucz podstawowy nigdy się nie zmienia w okresie istnienia jednostki.
Klucze klastrowe są kluczem definiującym fizyczne przechowywanie wierszy w tabeli. W większości przypadków nakładają się one na klucz podstawowy (identyfikator jednostki logicznej), ale nie jest to w rzeczywistości wymuszane ani wymagane. Gdy te dwa są różne, oznacza to, że w tabeli znajduje się unikalny indeks nieklastrowany, który implementuje klucz podstawowy. Klastrowe wartości kluczy mogą w rzeczywistości zmieniać się w okresie istnienia wiersza, co powoduje fizyczne przeniesienie wiersza w tabeli do nowej lokalizacji. Jeśli musisz oddzielić klucz podstawowy od klucza klastrowego (a czasami tak robisz), wybór dobrego klucza klastrowego jest znacznie trudniejszy niż wybór klucza podstawowego. Projekt klucza klastrowego zależy od dwóch głównych czynników:
- Popularny wzorzec dostępu do danych .
- Zagadnienia dotyczące przechowywania .
Wzorzec dostępu do danych . Rozumiem przez to sposób, w jaki tabela jest odpytywana i aktualizowana. Pamiętaj, że klucze klastrowe określają rzeczywistą kolejność wierszy w tabeli. W przypadku niektórych wzorców dostępu niektóre układy mają ogromne znaczenie pod względem szybkości zapytań lub aktualizacji współbieżności:
-
dane bieżące vs archiwalne. W wielu aplikacjach dane dotyczące bieżącego miesiąca są często używane, podczas gdy dane z przeszłości są rzadko dostępne. W takich przypadkach projekt tabeli wykorzystuje partycjonowanie tabeli według daty transakcji, często przy użyciu algorytmu przesuwanego okna. Partycja bieżącego miesiąca jest przechowywana na grupie plików znajdującej się na gorącym, szybkim dysku, zarchiwizowane stare dane są przenoszone do grup plików hostowanych na tańszym, ale wolniejszym magazynie. Oczywiście w tym przypadku klucz klastrowy (data) nie jest kluczem podstawowym (identyfikatorem transakcji). Rozdzielenie tych dwóch jest uzależnione od wymagań dotyczących skali, ponieważ optymalizator zapytań będzie w stanie wykryć, że zapytania są zainteresowane tylko bieżącą partycją, a nawet nie patrzeć na te historyczne.
-
Przetwarzanie stylu kolejki FIFO. W tym przypadku w tabeli występują dwa gorące punkty:ogon, w którym występują inserty (w kolejce), oraz główka, w której występują usunięcia (usuwanie). Klucz klastrowy musi wziąć to pod uwagę i zorganizować tabelę tak, aby fizycznie oddzielić położenie ogona i głowicy na dysku, aby umożliwić współbieżność między kolejkowaniem i usuwaniem z kolejki, np. za pomocą klucza kolejności w kolejce. W czystym kolejki ten klucz klastrowy jest jedynym kluczem, ponieważ w tabeli nie ma klucza podstawowego (zawiera wiadomości , a nie podmioty ). Ale w większości przypadków kolejka nie jest czysta, działa również jako magazyn jednostek i linia między kolejką i stół jest rozmazany. W tym przypadku istnieje również klucz podstawowy, który nie może być kluczem klastrowym:jednostki mogą być ponownie umieszczane w kolejce, zmieniając w ten sposób wartość klucza klastrowanego w kolejności umieszczania w kolejce, ale nie mogą zmieniać wartości klucza podstawowego. Niedostrzeżenie separacji jest głównym powodem, dla którego kolejki obsługiwane przez tabelę użytkownika są tak bardzo trudne do naprawienia i pełne zakleszczeń:ponieważ kolejkowanie i usuwanie z kolejki występują przeplatane w tabeli, zamiast zlokalizowane na końcu i na początku kolejki.
-
Przetwarzanie skorelowane. Jeśli aplikacja jest dobrze zaprojektowana, podzieli przetwarzanie skorelowanych elementów między swoje wątki robocze. Na przykład procesor jest zaprojektowany tak, aby miał 8 wątków roboczych (powiedzmy, że pasuje do 8 procesorów na serwerze), więc procesory dzielą między sobą dane, np. pracownik 1 pobiera tylko konta o nazwach A do E, pracownik 2 F do J itd. W takich przypadkach tabela powinna być faktycznie pogrupowana według nazwy konta (lub według klucza złożonego, który ma pierwszą literę nazwy konta w skrajnej lewej pozycji), tak, aby pracownicy lokalizowali swoje zapytania i aktualizacje w tabeli. Taki stół miałby 8 odrębnych punktów zapalnych, wokół obszaru, w którym każdy pracownik w tej chwili koncentruje się, ale ważne jest, aby nie nakładały się na siebie (brak blokowania). Ten rodzaj projektu jest powszechny w projektach OLTP o wysokiej przepustowości i w obciążeniach porównawczych TPCC, gdzie ten rodzaj partycjonowania odzwierciedla również lokalizację pamięci stron załadowanych do puli buforów (lokalizacja NUMA), ale ja robię dygresję.
Zagadnienia dotyczące przechowywania . Klucz klastrowy szerokość ma ogromne reperkusje w przechowywaniu stołu. Po pierwsze, klucz zajmuje miejsce na każdej stronie b-drzewa nie będącej liściem, więc duży klucz zajmie więcej miejsca. Drugim, często ważniejszym, jest to, że klucz klastrowy jest używany jako klucz wyszukiwania przez każdy klucz nieklastrowany, więc każdy klucz nieklastrowy będzie musiał przechowywać pełną szerokość klucza klastrowego dla każdego wiersza. To sprawia, że duże klucze klastrowe, takie jak varchar(256), i guids są złym wyborem dla kluczy indeksu klastrowego.
Ponadto wybór klucza ma wpływ na fragmentację indeksu klastrowanego, czasami drastycznie wpływając na wydajność.
Te dwie siły mogą czasami być antagonistyczne, wzorzec dostępu do danych wymaga pewnego dużego klucza klastrowego, co spowoduje problemy z przechowywaniem. W takich przypadkach potrzebna jest oczywiście równowaga, ale nie ma magicznej formuły. Mierzysz i testujesz, aby dotrzeć do najlepszego punktu.
Więc co z tego wszystkiego zrobimy? Zawsze zaczynaj od rozważenia klucza klastrowego, który jest również kluczem podstawowym w postaci entity_id IDENTITY(1,1) NOT NULL
. Oddziel je i odpowiednio uporządkuj tabelę (np. Podziel według daty), gdy jest to właściwe.