Czy powinienem użyć wielu kluczy podstawowych kolumn czy dodać nową kolumnę?

15

Mój obecny projekt bazy danych korzysta z klucza podstawowego z wieloma kolumnami do wykorzystania istniejących danych (które i tak byłyby unikalne) zamiast tworzenia dodatkowej kolumny przypisującej każdemu wpisowi dowolny klucz. Wiem, że jest to dozwolone, ale zastanawiałem się, czy jest to praktyka, z której mógłbym chcieć korzystać ostrożnie i ewentualnie unikać (podobnie jak goto w C).

Jakie są wady, które mogę zobaczyć w tym podejściu, lub powody, dla których mogę chcieć klucza z jedną kolumną?

Covar
źródło
2
Nie wiem, myślę, że byłoby lepiej na SO.
FrustratedWithFormsDesigner
2
@FrustratedWithFormsDesigner To może przejść do SO, ale myślę, że tu też działa, ponieważ wydaje się, że pytanie skupia się raczej na „jakie są zalety i wady tego podejścia”, a nie „jak zrobić X?”.
Adam Lear
@Anna Lear ♦: To „plusy i minusy” dotyczące decyzji projektowych, które będą miały bezpośredni i wyraźny wpływ na kodowanie, więc myślę, że SO byłoby lepszym miejscem.
FrustratedWithFormsDesigner

Odpowiedzi:

8

Zwykle, gdy masz tabelę z wielokolumnowym kluczem podstawowym, jest to wynik tabeli łączenia (wiele do wielu), która została podniesiona do rangi własnej jednostki (a zatem zasługuje na swój własny klucz podstawowy). Jest wielu, którzy twierdzą, że każda tabela dołączania POWINNA być jednostką domyślnie, ale jest to dyskusja na inny dzień.

Spójrzmy na hipotetyczną relację wiele do wielu:

Student * --- * Klasa

(uczeń może być w wielu klasach, klasa może mieć wielu uczniów).

Pomiędzy tymi dwiema tabelami pojawi się tabela połączeń o nazwie StudentClass (lub ClassStudent, w zależności od tego, jak ją napiszesz). Czasami chcesz śledzić rzeczy, na przykład kiedy uczeń był w klasie. Więc dodasz go do tabeli StudentClass. W tym momencie StudentClass stał się unikalnym bytem ... i należy mu nadać nazwę, aby go rozpoznać, np. Rejestracja.

Student 1 --- * Zapisy * --- 1 klasa

(uczeń może mieć wiele zapisów, każde zapisanie jest na jedną klasę (lub odwrotnie, klasa może mieć wiele zapisów, każde zapisanie jest na jednego ucznia).

Teraz możesz zapytać, na przykład, ilu uczniów zapisano na zajęcia Chemia 101 w ubiegłym roku? Lub w jakich zajęciach uczestniczył student John Doe, uczęszczając na Uniwersytet Acme? Było to możliwe bez oddzielnego klucza podstawowego, ale kiedy masz klucz podstawowy do rejestracji, łatwiej byłoby zapytać o te zapisy (według identyfikatora), ilu uczniów otrzymało ocenę pozytywną?

Ustalenie, czy jednostka zasługuje na PK, sprowadza się do tego, ile zapytań (lub manipulacji) wykonasz dla tej jednostki. Załóżmy na przykład, że chcesz dołączyć zadania wykonane dla ucznia w klasie. Logiczne miejsce, w którym można dołączyć ten byt (Przypisanie), byłoby w encji rejestracji. Nadanie rejestracji własnego klucza podstawowego uprościłoby zapytania dotyczące przypisania.

Michael Brown
źródło
1
Więc dodasz go do tabeli StudentClass. W tym momencie StudentClass stał się unikalną jednostką ... i należy mu nadać nazwę, aby go rozpoznać, np. Rejestracja. To taka prosta rzecz, ale robi to tyle wartości!
Botis,
8

Sensowne jest posiadanie osobnej kolumny identyfikatora. Jeśli chcesz uzyskać coś ze swojej tabeli bazy danych, łatwiej jest zrobić:

SELECT whatever FROM table WHERE id=13

niż WYBIERZ cokolwiek z tabeli GDZIE col1 = „val1” AND col2 = „val2” AND col3 = „val3”

Na przykład w aplikacji internetowej tłumaczy się na adres URL wyglądający tak:

www.somewebsite.com/somepage.php?id=13

lub tak:

www.somewebsite.com/somepage.php?col1=val1&col2=val2&col3=val3
podczerwień
źródło
4
I o wiele łatwiej jest dodać powiązaną tabelę, gdy można utworzyć link do identyfikatora zamiast kilku kolumn
CaffGeek
3
Przepraszam, w tym momencie muszę -1, ponieważ A) nie jest czarno-biały. Dodanie kolumny identyfikatora zawiera negatywy, takie jak miejsce i czas generowania nowego identyfikatora. Ponadto może to powodować dodatkowe sprzężenia lub SELECTzapytania. I, B) , nie mam pojęcia, w jaki sposób powoduje to jakiekolwiek wymagania dotyczące adresów URL (chyba że pracujesz ze złym frameworkiem). Moje adresy URL nie zawierają ciągów zapytań ?id=13, nie mówiąc już o nich ?col1=val1&col2=val2&col3=val3.
Nicole,
2
@renesis: Ta strona ma unikalne pytania i użytkowników, którzy są w adresach URL. Jest to jednak szczególny przypadek, ponieważ te dane nie ulegają zmianie.
Michael K
1
@Reneesis, większość (być może wszystkie) współczesnych baz danych ma typy liczb całkowitych auto_increment, które mogą generować identyfikatory automatycznie i bezpiecznie i zgłaszać je z powrotem za pomocą zapytania SQL lub wywołania funkcji biblioteki. Lub w środowisku rozproszonym używasz dużego losowego skrótu. Niektóre bazy danych utworzą nawet dla ciebie ukrytą kolumnę identyfikacyjną, jeśli nie masz jej już w tabeli.
GrandmasterB,
@Michael - nie powiedziałem, że identyfikatory nigdy nie są w adresach URL. Oczywiście że są. Jeśli masz adresy URL reprezentujące wiersz danych, to tak, dane te prawdopodobnie powinny mieć unikalny identyfikator. Chyba że jakaś inna część adresu URL zawiera już inne części klucza wielokrotnego. @GrandmasterB Żadna z dwóch ostatnich firm, dla których pracowałem (ponad 6 lat), które używają MySQL (jedna również obsługuje Oracle i SQL Server), nie były w stanie korzystać z automatycznego przyrostu ani dużego losowego skrótu.
Nicole,
8

Zasadniczo pytasz, czy powinieneś użyć klawiszy zastępczych czy naturalnych (w twoim przypadku brzmi to jak złożone klawisze naturalne). Oto świetny artykuł: http://www.agiledata.org/essays/keys.html

Wolę klucze zastępcze, ponieważ upraszczają administrację przez całe życie DB (nigdy nie musisz się martwić implikacją zmiany znaczenia kluczy, co nigdy nie powinno się zdarzyć, ale dzieje się tak w każdym prawdziwym systemie, w którym zaangażowani są ludzie). Jeśli jednak w bazie danych jest wiele tabel „wyszukiwania” (tj. Tabel, które są w zasadzie parami klucz: para wartości), wówczas klucze zastępcze mogą być kłopotliwe, ponieważ musisz dołączyć te tabele do zapytania, aby uzyskać znaczące wyniki.

Załóżmy na przykład, że masz dwa podmioty: adres i kraj.

  • Relacja to: Adres * ----- 1 Kraj
  • Podmiot Country jest w zasadzie kluczem: parą wartości (np. USA: Stany Zjednoczone, Kalifornia: Kanada, MX: Meksyk itp.)
  • Aby wysłać zapytanie o tę strukturę dla wszystkich adresów w USA:

select * from Address where CountryCode = 'US'

  • Aby wykonać to samo zapytanie za pomocą kluczy zastępczych:

select Address.* from Address join Country on Address.CountryID = Country.ID where Country.Code = 'US'

Nie mam nic przeciwko mandowaniu naturalnych kluczy do tabel odnośników i zastępczych kluczy do wszystkiego innego, jeśli jestem całkiem pewien, że naturalne klucze nie będą się zmieniać zbyt często, jeśli w ogóle.

Curtis Batt
źródło
5

To zależy od sposobu dostępu do danych. Jeśli wykonujesz wiele przeszukiwania częściowego klucza (w którym wybierasz rekordy na podstawie powiedzmy tylko dwóch z trzech kluczy), będziesz chciał zachować klucze wieloczęściowe. OTOH, jeśli masz wiele relacji 1: 1 z innymi tabelami, prawdopodobnie lepiej jest mieć klucz zastępczy.

TMN
źródło
1

Lubię zawsze mieć zastępczy klucz podstawowy dla każdej tabeli. Ale nie ma wielu „trudnych” powodów, aby wymusić to, co słyszałem.

Jeden raz, kiedy kiedykolwiek ugryzł mnie wielokolumnowy klucz naturalny, to ORM. Czasami miałem problemy z kluczem podstawowym z wieloma kolumnami przy użyciu Linq To Entities.

Mike M.
źródło
1

Nigdy nie mów nigdy, ale połączenie na 4 kolumnach jest uciążliwe. Im więcej kolumn masz z inteligentnymi danymi, tym większa szansa, że ​​te wartości się zmienią. Bazy danych można skonfigurować w celu zachowania spójności referencyjnej dzięki aktualizacjom kaskadowym.

Zawsze możesz utworzyć kolejny indeks do obsługi unikalnych wartości.

Wydajność jest prawdopodobnie nieznaczna w większości przypadków, ale możesz przetestować swoje zapytania za pomocą i bez klucza surragate.

JeffO
źródło
0

Trudno mi znaleźć dobry powód, aby wprowadzić osobny klucz, ale tak jak powiedziałeś, wielu ludzi włożyło go.

Nie znajduję tej pomocy (szczególnie w przypadku przechowywania) w przypadku tabel faktów / szczegółów. Przykład kanoniczny tabela faktów sprzedaży z (klucz_klienta, klucz_sklepu, klucz_produktu) z ilością nie ma sensu mieć klucza na poziomie rekordu.

Jé Queue
źródło
0

Posiadanie automatycznego przyrostu PK zmniejsza kłopot, jeśli okaże się, że klucz złożony może w rzeczywistości mieć duplikaty.

Paul Nathan
źródło
0

Dobra dyskusja sięga 2002 roku na Ask Tom . Jest to specyficzne dla Oracle, ale szersza dyskusja jest istotna niezależnie od używanej bazy danych.

Rhys Gibson
źródło