Czy powinienem dodać pole automatycznego przyrostu / TOŻSAMOŚCI do tabeli odsyłaczy tylko do celów PK?

9

Dodaję następującą tabelę odsyłaczy do mojej bazy danych hostowanej przez SQL Server:

company_id bigint not null (FK)
org_path nvarchar (2048) not null

company_idPole odnosi się do idpola w innej tabeli (w którym to klucz podstawowy).

Biorąc pod uwagę, że może istnieć wiele rekordów z tym samym company_id, każdy klucz podstawowy musiałby używać obu pól. Nie mogę jednak utworzyć klucza przy użyciu obu pól, ponieważ org_pathjest on zbyt długi dla programu SQL Server.

Co do org_pathtego, jest to jedyna tabela, w której istnieje. Istnieje prawdopodobieństwo, że zapytania do tej tabeli będą wymagały podania wszystkich wpisów lub wszystkich org_pathwpisów według company_id. Innymi słowy, wydaje się wątpliwe, czy ten stolik zostanie kiedykolwiek zapytany org_path. Ponadto jest mało prawdopodobne, że org_pathzostanie zaktualizowany, a bardziej prawdopodobne wstawienie i - prawdopodobnie rzadko - usunięcie.

Oczekuję, że całkowita liczba wierszy będzie w niskich tysiącach.

Powodem jest także nvarchar (2048)to, że wartość musi naśladować to w bazie danych innej firmy. Typowym przykładem będzie coś takiego

\Translation Providers\[customer name]\[order name]\

i może zawierać znaki diakrytyczne.

Moje pytanie brzmi zatem: czy bardziej efektywne byłoby dodanie idpola automatycznego przyrostu i użycie go w połączeniu z company_idkluczem podstawowym, czy też spowodowałoby to niepotrzebne obciążenie - i czy fakt, że company_idjest to klucz podstawowy w innej tabeli, ma jakieś znaczenie? efekt tutaj?

awj
źródło

Odpowiedzi:

7

W przypadku comany_idsamego nieunikalnego indeksu klastrowego SQL Server automatycznie doda 4-bajtowy unikatowy integer do wszystkich duplikatów (tj. Drugi i kolejny dla wartości klucza) klastrowanych kluczy indeksu, aby uczynić go unikalnym. Nie jest to jednak narażone na działanie użytkownika.

Zaletą dodania własnego unikalnego identyfikatora jako kolumny klucza dodatkowego jest to, że możesz nadal wyszukiwać według, company_idale także bardziej wydajnie wyszukiwać poszczególne wiersze (używając company_id, identitycolraczej niż company_idz resztkowym predykatem org_path). Indeks klastrowy byłby wówczas unikalny company_id, identitycol, więc nie byłyby dodawane żadne ukryte unikatniki.

Ponadto, jeśli skończysz z duplikatami (company_id,org_path), posiadanie kolumny z wyraźną tożsamością (rodzaj „odsłoniętego unikalizatora”) ułatwi wybranie jednego z nich do usunięcia lub aktualizacji.

Martin Smith
źródło
12

Jedną rzeczą do rozważenia jest to, że klucz podstawowy i indeks klastrowany to nie to samo. Klucz podstawowy jest ograniczeniem i dotyczy zasad, według których dane żyją (tj. Integralności danych); nie ma to nic wspólnego z wydajnością / wydajnością. Klucz podstawowy wymaga, aby kolumny klucza były unikalne (w kombinacji) i NIE NULL (indywidualnie). PK jest egzekwowane za pomocą unikalnego indeksu, chociaż może być klastrowany lub nieklastrowany.

Indeks klastrowy to sposób fizycznego (tj. Na dysku) porządkowania danych w tabeli i zajmowania się wydajnością; nie ma to nic wspólnego z integralnością danych. Indeks klastrowany możewymagają, aby kolumny kolumn były unikalne (w kombinacji), ale nie musi. Ponieważ jednak Indeks klastrowy jest fizyczną kolejnością danych, musi jednoznacznie identyfikować każdy wiersz bez względu na wszystko. Jeśli więc nie ustawisz, aby wymagała unikatowości, utworzy własną unikalność poprzez ukrytą 4-bajtową kolumnę „unikatowość”. Ta kolumna jest zawsze dostępna w nie unikatowych indeksach klastrowych, ale nie zajmuje miejsca, gdy pola kluczowe są unikalne (w kombinacji). Aby zobaczyć z pierwszej ręki, jak działa ta kolumna „unikatowy” (zarówno w indeksie klastrowanym, jak i w wpływie na indeksy nieklastrowane), zapoznaj się z tym skryptem testowym, który zamieściłem na skrypcie PasteBin: T-SQL, aby przetestować rozmiar unikalizatora .

Stąd główne pytanie:

czy bardziej efektywne byłoby dodanie idpola automatycznego przyrostu i użycie go w połączeniu z company_idkluczem podstawowym, czy też spowodowałoby to niepotrzebne obciążenie

łączy te dwie koncepcje, więc należy je rozwiązać osobno, choć zdecydowanie nakładają się na siebie.

Czy IDENTITYkolumna powinna zostać dodana, czy byłby to niepotrzebny narzut?

Jeśli dodasz INT IDENTITYkolumnę i użyjesz jej do utworzenia PK, zakładając, że będzie to PK w klastrach, który doda 4 bajty do każdego wiersza. Ta kolumna jest widoczna i użyteczna w zapytaniach. To mógłby być dodawany do innych tabel jako klucz obcy, chociaż w tym konkretnym przypadku, że nie stanie.

Jeśli nie dodasz INT IDENTITYkolumny, nie możesz utworzyć PK w tej tabeli. Możesz jednak nadal tworzyć indeks klastrowany na stole, o ile nie skorzystasz z tej UNIQUEopcji. W takim przypadku SQL Server doda ukrytą kolumnę o nazwie „uniquifier”, która zachowuje się jak opisano powyżej. Ponieważ kolumna jest ukryta, nie można jej używać w zapytaniach ani jako odwołania do kluczy obcych.

Jeśli chodzi o wydajność, opcje te są mniej więcej takie same. Tak, zajmie nieco mniej miejsca zajmując nie unikatowy indeks klastrowy, ponieważ niektóre wiersze (z początkowymi unikatowymi wartościami kluczy) zajmują 0 bajtów, podczas gdy wszystkie wiersze w IDENTITY/ PK zajmą 4 bajty. Ale nie będzie wystarczającej liczby 0-bajtowych wierszy (szczególnie przy oczekiwanej małej liczbie wierszy), aby kiedykolwiek zauważyć różnicę, nie mówiąc już o przewadze wygody korzystania z IDkolumny w zapytaniach.

INT IDENTITY kolumna lub Hash z org_pathTrwały Kolumna komputerowej?

Biorąc pod uwagę, że nie będziesz przeglądać wierszy na podstawie org_pathwartości, nie ma sensu dodawanie narzutu w utrwalonej kolumnie obliczeniowej oraz konieczność obliczania tego skrótu w zapytaniach w celu dopasowania go do kolumny obliczonej (to był mój oryginalna sugestia, dostępna tutaj w historii zmian , która była oparta na wstępnym sformułowaniu / szczegółach pytania). W tym konkretnym przypadku INT IDENTITYkolumna „ID” jest prawdopodobnie najlepsza.

Kolejność kolumn klucza

Biorąc pod uwagę, że IDkolumna rzadko, jeśli w ogóle, będzie używana w zapytaniach, a biorąc pod uwagę, że dwa główne przypadki użycia to uzyskanie „wszystkich wierszy” lub „wszystkich wierszy dla danego company_id”, utworzę PK na company_id, id. A ponieważ oznacza to, że wiersze nie są wstawiane sekwencyjnie, podaję wartość FILLFACTOR90. Konieczne będzie również regularne utrzymywanie indeksu w celu zmniejszenia fragmentacji.

Drugie Pytanie

czy fakt, że company_id jest kluczem podstawowym w innej tabeli, ma tu jakikolwiek wpływ

Nie.

Wyzwalacz

Ponieważ org_pathwartości w obrębie company_idsą unikalne, powinieneś nadal tworzyć wyzwalacz, INSERT, UPDATEaby to wymusić. W Trigger wykonaj IF EXISTSzapytanie, które prawdopodobnie wykonuje a COUNT(*)i GROUP BY company_id, org_path. Jeśli coś zostanie znalezione, wydaj polecenie a, ROLLBACKaby anulować operację DML, a następnie RAISERRORpowiedz, że istnieją duplikaty.

Porównanie

W mojej początkowej odpowiedzi (opartej na oryginalnych sformułowaniach / rzadkich szczegółach pytania i dostępnej tutaj w historii zmian ) zasugerowałem użycie binarnego (tj. _BIN2) Sortowania. Teraz, gdy mamy już wgląd w to, co dokładnie org_pathjest, nie polecam używania binarnego sortowania. Ponieważ nie będzie znaków diakrytycznych, to nie chcą skorzystać z równoważności językowych.

Solomon Rutzky
źródło
Daj nam kontynuować tę dyskusję w czacie .
Solomon Rutzky
0

Dlaczego potrzebujesz PK?

Dlaczego nie skorzystać z company_id jako indeksu nieklastrowanego?

Powiedziałeś, że najczęściej wyszukiwane są wszystkie wpisy lub według company_id
Rzadko aktualizuj
Rzadko usuwaj
ścieżkę org, jest to jedyna tabela, w której istnieje

Odpowiedź Martina Smitha może dać ci to, czego potrzebujesz
Nie jestem zaznajomiony z automatycznym dodawaniem unikatowego 4-bajtowego unikalizatora liczb całkowitych
Być może coś mi brakuje, ale jeśli nie masz zaindeksowanych innych kolumn, nie widzę sensu w tym przypadku użycia

Jeśli obawiasz się o DRI, tabele powinny używać tabeli Company jako FK dla company_id

paparazzo
źródło
Hej. Odnośnie do „ Dlaczego po prostu nie użyć id_firmowego jako indeksu nieklastrowego? ”: Ponieważ miałoby to 2 wady: 1) zajęłoby to jeszcze 1 miejsce, podczas gdy indeks klastrowany jest tabelą, więc nie ma dodatkowego elementu, i 2) nadal wymagałoby wyszukiwania RID, aby uzyskać pole NVARCHAR, chyba że była to INCLUDEkolumna, ale jest to jeszcze gorsze, ponieważ polega jedynie na powieleniu tabeli. To prawda, że ​​PK nie jest konieczne; ważną częścią jest Indeks klastrowy. Ale kiedy już masz TOŻSAMOŚĆ, równie dobrze możesz iść z PK. I proszę zobaczyć nowy link w mojej odpowiedzi na przewodnik po Uniquifier ifier
Solomon Rutzky
@srutzky Ale unika 4-bajtowego unikalizatora liczb całkowitych, więc widzę to jako pranie
paparazzo
Przy mniej niż 10 000 wierszy nie będzie to miało znaczenia; prawdopodobnie musisz być w milionach wierszy, zanim zauważysz efekt zaledwie 4 bajtów. Tak więc dla zapytania „pobierz wszystkie wiersze” nie ma żadnej różnicy w żadnej z tych opcji. Ale w przypadku zapytania „get for company_id = @param” pomocne będzie fizyczne uporządkowanie danych przez company_id, zwłaszcza gdy nie trzeba wykonywać wyszukiwania RID dla każdego wiersza.
Solomon Rutzky
@srutzky Wash to pranie - 10K lub 1G. To tylko kwestia do rozważenia przez PO.
paparazzo