Tworzę bazę danych SQL Server 2012 i mam wątpliwości co do kolumn nvarchar jako kluczy podstawowych.
Mam ten stół:
CREATE TABLE [dbo].[CODES]
(
[ID_CODE] [bigint] IDENTITY(1,1) NOT NULL,
[CODE_LEVEL] [tinyint] NOT NULL,
[CODE] [nvarchar](20) NOT NULL,
[FLAG] [tinyint] NOT NULL,
[IS_TRANSMITTED] [bit] NOT NULL DEFAULT 0,
CONSTRAINT [PK_CODES] PRIMARY KEY CLUSTERED
(
[CODE_LEVEL] ASC,
[CODE] ASC
)
)
Ale teraz chcę użyć [CODE]
kolumny jako klucza podstawowego i usunąć [ID_CODE]
kolumnę.
Czy jest jakaś kwestia lub kara, jeśli mam NVARCHAR
kolumnę jako PRIMARY KEY
?
[CODE]
wartość kolumny musi być unikalna, więc pomyślałem, że mogę ustawić UNIQUE
ograniczenie dla tej kolumny.
Czy muszę używać [CODE]
jako klucza podstawowego, czy lepiej jest, jeśli ustawię UNIQUE
ograniczenie dla [CODE]
kolumny?
sql-server
primary-key
unique-constraint
VansFannel
źródło
źródło
CODE
kolumna powinna być unikalna, ale nie klucz podstawowy. Podejrzewam, że zawiera informacje. Jeśli informacje te można w jakikolwiek sposób zmienić,CODE
należy je zmienić lub być nieaktualne. To sprawiłoby, że Twój Klucz Podstawowy byłby niestabilny i nie widzę, żeby to się dobrze skończyło. Najlepiej, aby Twój PK był tylko kluczem, a Twój KOD może robić, co lubi. Po prostu opinia.Odpowiedzi:
Tak, absolutnie istnieją negatywne konsekwencje używania łańcucha zamiast typu liczbowego dla klucza podstawowego, a tym bardziej, jeśli PK jest klastrowany (co w rzeczywistości tak jest w twoim przypadku). Jednak stopień, w jakim widzisz efekt (y) użycia pola ciągu, jest funkcją a) liczby wierszy w tej tabeli oraz b) liczby wierszy w innych tabelach z kluczem obcym dla tej PK. Jeśli masz tylko 10 tys. Wierszy w tej tabeli i 100 tys. Wierszy w kilku innych tabelach, które FK do tej tabeli za pośrednictwem tego pola, być może nie będzie to tak zauważalne. Ale te efekty z pewnością stają się bardziej zauważalne wraz ze wzrostem liczby wierszy.
Należy wziąć pod uwagę, że pola w indeksie klastrowanym są przenoszone do indeksów nieklastrowanych. Więc nie patrzysz tylko na 40 bajtów na wiersz, ale (40 * jakiś_numer) bajtów. I w dowolnych tabelach FK masz te same 40 bajtów w wierszu, a częściej w tym polu będzie indeks nieklastrowany, ponieważ jest on używany w połączeniach, więc teraz jest naprawdę podwojony w tabelach, do których FK ten. Jeśli ktoś uważa, że 40 bajtów * 1 milion wierszy * 10 jego kopii nie ma się czym martwić, zobacz mój artykuł Dysk jest tani! ORLY? które wyszczególniają wszystkie (lub przynajmniej większość) obszary, na które wpływa ta decyzja.
Inną rzeczą do rozważenia jest to, że filtrowanie i sortowanie ciągów, szczególnie gdy nie jest używane sortowanie binarne (zakładam, że używasz domyślnej bazy danych, która zazwyczaj nie rozróżnia wielkości liter) jest znacznie mniej wydajne (tj. Trwa dłużej) niż przy użyciu
INT
/BIGINT
. Wpływa to na wszystkie zapytania filtrujące / łączące / sortujące w tym polu.Dlatego użycie czegoś podobnego
CHAR(5)
byłoby prawdopodobnie OK dla klastrowanego PK, ale głównie, jeśli zostało to również zdefiniowane za pomocąCOLLATE Latin1_General_100_BIN2
(lub czegoś takiego).I czy wartość
[CODE]
kiedykolwiek może się zmienić? Jeśli tak, to jeszcze więcej powodów, aby nie używać go jako PK (nawet jeśli ustawisz FK naON UPDATE CASCADE
). Jeśli to nie może lub nigdy się nie zmieni, to dobrze, ale wciąż istnieje wystarczający powód, aby nie używać go jako PK.Oczywiście pytanie może być niepoprawnie sformułowane, ponieważ wydaje się, że masz już to pole w swoim PK.
Niezależnie od tego, jak dotąd najlepszą opcją jest użycie
[ID_CODE]
jako klastrowanego PK, użycie tego pola w powiązanych tabelach jako FK i zachowanie go[CODE]
jakoUNIQUE INDEX
(co oznacza, że jest to „klucz zastępczy”).Aktualizacja
Trochę więcej informacji na podstawie tego pytania w komentarzu do tej odpowiedzi:
Wszystko zależy od bardzo wielu czynników, z których niektóre już wspomniałem, ale powtórzę:
Klucz podstawowy to sposób identyfikacji pojedynczego wiersza, niezależnie od tego, czy jest do niego przypisany jakikolwiek klucz obcy. Sposób, w jaki system wewnętrznie identyfikuje wiersz, jest związany, ale niekoniecznie taki sam, z tym, jak użytkownicy identyfikują się / ten wiersz. Każda kolumna NOT NULL z unikatowymi danymi może działać, ale należy wziąć pod uwagę kwestie praktyczne, zwłaszcza jeśli PK są w rzeczywistości przywołane przez dowolne FK. Na przykład identyfikatory GUID są unikalne i niektórzy ludzie naprawdę lubią ich używać z różnych powodów, ale są dość złe dla indeksów klastrowych (
NEWSEQUENTIALID
jest lepszy, ale nie idealny). Z drugiej strony, identyfikatory GUID są w porządku jako klucze alternatywne i są używane przez aplikację do wyszukiwania wiersza, ale JOIN są nadal wykonywane przy użyciu INT (lub podobnej) PK.Do tej pory nie powiedziałeś nam, jak
[CODE]
pole wpasowuje się w system ze wszystkich stron, poza tym, że wspomniałeś, że tak właśnie wyglądasz wiersze, ale czy to dotyczy wszystkich zapytań czy tylko niektórych? W związku z tym:Jeśli chodzi o
[CODE]
wartość:W odniesieniu do tej tabeli:
[CODE]
lub[ID_CODE]
) są używane w innych tabelach, nawet jeśli nie są jawnie obce?[CODE]
jedyne pole służy do uzyskiwania pojedynczych wierszy, to jaki cel[ID_CODE]
służy temu polu? Jeśli nie jest używany, dlaczego ma go w ogóle (co może zależeć od odpowiedzi na „Czy[CODE]
pole może się kiedykolwiek zmienić?”)?Tej decyzji nie można podjąć wyłącznie na pytanie „NVARCHAR tak czy nie?”. Jeszcze raz powiem, że ogólnie rzecz biorąc nie uważam tego za dobry pomysł, ale z pewnością są chwile, kiedy jest w porządku. Biorąc pod uwagę tak małą liczbę pól w tej tabeli, jest mało prawdopodobne, że istnieje więcej lub przynajmniej niewiele indeksów. Więc może być dobrze, tak czy inaczej,
[CODE]
jako indeks klastrowany. A jeśli żadne inne tabele nie odwołują się do tej tabeli, może być również w porządku, czyniąc ją PK. Ale jeśli inne tabele odwołują się do tej tabeli, wybrałbym[ID_CODE]
pole jako PK, nawet jeśli nie jest klastrowane.źródło
[ID_CODE]
, jakPRIMARY KEY
, najlepszym rozwiązaniem, jeśli używam[CODE]
kolumna patrzeć w górę tabeli?Musisz oddzielić pojęcia:
klucz podstawowy to koncepcja projektowa , logiczna właściwość wpisów w tabeli. Powinien być niezmienny przez cały czas trwania wpisu w tabeli i powinien być kluczem używanym w aplikacji do odwoływania się do wpisu.
indeks klastrowany to koncepcja pamięci , właściwość fizyczna. Powinien być najczęstszą ścieżką dostępu do zapytań, powinien służyć jako indeks pokrywający dla większości przypadków i spełniać jak najwięcej zapytań o zakres, jak to możliwe.
Nie jest wymagany, aby klucz podstawowy był indeksem klastrowym. Możesz mieć
ID_CODE
jako PK i(CODE_LEVEL, CODE)
jako klucz klastrowany. Albo na odwrót.Większy klucz klastrowy ma pewne negatywne konsekwencje, ponieważ szerszy klucz oznacza mniejszą gęstość stron indeksu i większy rozmiar zużywany we wszystkich indeksach nieklastrowanych. na ten temat rozlano już tony atramentu, np. zacznij od Więcej uwag na temat klucza klastrowania - debata indeksu klastrowego trwa! .
Ale sedno sprawy polega na tym, że wybór klastrowanego klucza indeksu jest przede wszystkim kompromisem. Z jednej strony masz wymagania co do wielkości zapasów z ogólnymi reperkusje w większej wydajności (Key -> większy rozmiar -> przepustowość więcej IO i IO jest prawdopodobnie najbardziej deficytowym zasobem masz). Z drugiej strony wybranie niewłaściwego klucza klastrowego w imię oszczędności miejsca może mieć konsekwencje w zakresie wydajności zapytań, często gorsze niż problemy wynikające z szerokiego klucza.
Jeśli chodzi o wybór klucza podstawowego, nie powinno to nawet stanowić problemu: model danych, logika aplikacji powinny dyktować, co to jest klucz podstawowy.
To powiedziawszy, mój 2c: nie
NVARCHAR(20)
jest szeroki. Jest idealnie akceptowalnym rozmiarem klucza klastrowego, nawet dla dużego stołu.źródło
[ID_CODE]
jestPRIMARY KEY
to najlepsza opcja, jeśli używam[CODE]
kolumny (i być może[CODE_LEVEL]
) do wyszukiwania w tabeli?[CODE]
kolumnę jako klucz podstawowy.Nigdy nie pozwoliłbym, aby ktoś zrobił
nvarchar(20)
PK w mojej bazie danych. Marnujesz miejsce na dysku i pamięć podręczną. Każdy indeks w tej tabeli i wszystkie FK do niej odzwierciedlają tę szeroką wartość. Może char (20), jeśli potrafią to uzasadnić. Jakie dane próbujesz przechowywaćCODE
? Czy naprawdę potrzebujesz przechowywać znaki nvarchar? Staram się, aby wartości PK były „wewnętrzne”, niewidoczne dla użytkowników, i staram się zachować wartości, które są wyświetlane osobno. Wyświetlane wartości czasami wymagają zmiany, co staje się bardzo problematyczne w przypadku PK i FK.Czy zdajesz sobie również sprawę, że „tożsamość biginta (1,1)” może zwiększyć się do 9 223 372,036,854,775,807?
O ile nie budujesz tej bazy danych dla Google, czy normalność
int identity (1,1)
z limitem ponad 2 miliardów nie wystarczy?źródło
[ID_CODE]
, jakPRIMARY KEY
, najlepszym rozwiązaniem, jeśli używam[CODE]
kolumna patrzeć w górę tabeli? Dzięki.Nie powinno być żadnej nieodłącznej / zauważalnej kary innej niż ryzyko użycia szerokich kluczy podczas korzystania z nvarchar / varchar, jeśli nie jest się świadomym. Zwłaszcza jeśli zaczniesz łączyć je w klucze kompozytowe.
Ale w twoim przykładzie (20) długości powinieneś być w porządku i nie martwiłbym się tym zbytnio. Ponieważ jeśli KOD polega głównie na wyszukiwaniu danych - indeks klastrowany na to brzmi bardzo rozsądnie.
Należy jednak rozważyć, czy rzeczywiście jest to klucz podstawowy, czy tylko unikalny (klastrowany) indeks. Istnieje (niewielka) różnica między indeksem klastrowym a kluczem podstawowym (w zasadzie - klucz podstawowy identyfikuje dane, ale indeks polega na wyszukiwaniu danych), więc jeśli chcesz, możesz równie łatwo ustawić kod ID_Code jak klucz podstawowy i utwórz unikalny indeks klastrowy na KOD. (uwaga: SQL Server automatycznie zmieni klucz podstawowy w indeks klastrowany, chyba że samodzielnie utworzysz indeks klastrowany)
Zastanów się także, czy faktycznie potrzebujesz ID_Code, teraz masz unikalny KOD.
źródło
NVARCHAR(20)
ma 40 bajtów (maks.), A ponieważ jest to kolumna o zmiennej długości , nie jest to naprawdę najlepszy wybór dla indeksu klastrowego.ID_CODE
bycie tutajBIGINT IDENTITY
byłoby znacznie lepszym wyborem!