Czy można mieć klucz obcy jako klucz podstawowy?


103

Mam dwa stoliki:

  • Użytkownik (nazwa użytkownika, hasło)
  • Profil (identyfikator profilu, płeć, data urodzenia, ...)

Obecnie używam tego podejścia: każdy rekord profilu ma pole o nazwie „userId” jako klucz obcy, który łączy się z tabelą użytkownika. Kiedy użytkownik rejestruje się, automatycznie tworzony jest jego rekord profilu.

Jestem zdezorientowany moją sugestią znajomego: aby mieć pole „userId” jako klucz obcy i podstawowy i usunąć pole „profileId”. Które podejście jest lepsze?


3
Entity Framework generuje to (z kodem najpierw) dla relacji zeroOrOne (i jeden) -to-one. Więc ... to możliwe. Czy to najlepszy sposób ... To kolejne pytanie. Ale to ważne. Nigdy tego nie robiłem podczas tworzenia własnych baz danych (ale nawet o tym nie myślałem).
Raphaël Althaus

Odpowiedzi:


132

Klucze obce są prawie zawsze „Zezwalaj na duplikaty”, co czyni je nieodpowiednimi jako klucze podstawowe.

Zamiast tego znajdź pole, które jednoznacznie identyfikuje każdy rekord w tabeli, lub dodaj nowe pole (albo automatycznie zwiększającą się liczbę całkowitą, albo identyfikator GUID), które będzie działać jako klucz podstawowy.

Jedynym wyjątkiem są tabele z relacją jeden do jednego , w których klucz obcy i klucz podstawowy tabeli połączonej są takie same.


74
Złożony klucz podstawowy składający się z dwóch kluczy obcych doskonale nadaje się również do implementowania relacji wiele do wielu.
prawostronny

1
@rezadru: Na pewno nie zgadzam się z prawostronnym składnikiem, ale klucz zastępczy jest prawie zawsze lepszym wyborem.
Robert Harvey

4
Nic na temat klucza obcego nie mówi, że jest to 1 do wielu (lub „zezwalaj na duplikaty”, jak napisano). Kluczowe ograniczenia i niepowtarzalność to dwa odrębne pojęcia w bazie danych i można je łatwo mieszać tak samo, jak dodawanie indeksu (co byłoby trzecim odrębnym pojęciem).
blindguy

40

Klucze podstawowe zawsze muszą być unikalne, klucze obce muszą zezwalać na wartości nieunikalne, jeśli tabela jest relacją jeden do wielu. Używanie klucza obcego jako klucza podstawowego jest całkowicie w porządku, jeśli tabela jest połączona relacją jeden do jednego, a nie relacją jeden do wielu. Jeśli chcesz, aby ten sam rekord użytkownika miał możliwość posiadania więcej niż 1 powiązanego rekordu profilu, użyj oddzielnego klucza podstawowego, w przeciwnym razie trzymaj się tego, co masz.


11

Tak, legalne jest posiadanie klucza podstawowego będącego kluczem obcym. To rzadki konstrukt, ale dotyczy:

  • relacja 1: 1. Tych dwóch tabel nie można połączyć w jedną, ponieważ różne uprawnienia i przywileje mają zastosowanie tylko na poziomie tabeli (od 2017 r. Taka baza danych byłaby dziwna).

  • relacja 1: 0..1. Profil może istnieć lub nie, w zależności od typu użytkownika.

  • Wydajność jest problemem, a projekt działa jak partycja: rzadko uzyskuje się dostęp do tabeli profili, jest hostowana na oddzielnym dysku lub ma inne zasady dzielenia na fragmenty w porównaniu z tabelą użytkowników. Nie miałoby sensu, gdyby przechowywanie z podkreśleniem było kolumnowe.


Wystąpiłby negatywny wynik, gdyby stoły były często łączone, co prowadzi do normalnego zalecenia, że ​​1 stół jest lepszy. W niektórych przypadkach dostęp do danych jest zawsze dostępny osobno, a nie łączony, a posiadanie dwóch tabel w relacji 1: 1 może przynieść korzyści organizacyjne.
blindguy

4

Powszechnie uważa się, że utrzymywanie relacji jeden do jednego jest złą praktyką. Dzieje się tak, ponieważ możesz po prostu przedstawić dane w jednej tabeli i osiągnąć ten sam wynik.

Są jednak przypadki, w których możesz nie być w stanie wprowadzić tych zmian w tabeli, do której się odwołujesz. W tym przypadku nie ma problemu z używaniem klucza obcego jako klucza podstawowego. Pomocne może być posiadanie klucza złożonego składającego się z automatycznie zwiększającego się unikalnego klucza podstawowego i klucza obcego.

Obecnie pracuję nad systemem, w którym użytkownicy mogą się zalogować i wygenerować kod rejestracyjny do użycia z aplikacją. Z powodów, w które nie wchodzę, nie mogę po prostu dodać wymaganych kolumn do tabeli użytkowników. Więc idę trasą jeden do jednego z tabelą kodów.


2
Zgadzam się z tobą głównie, że posiadanie wszystkich danych w tej samej tabeli w dodatkowych kolumnach ma wiele zalet. Chociaż wrt this .. "możesz po prostu przedstawić dane w jednej tabeli i osiągnąć ten sam wynik" ..: posiadanie oddzielnej tabeli może być przydatne, na przykład tutaj, jeśli wpis w tabeli profilu jest opcjonalny. Na przykład każdy klient banku może nie mieć rejestracji w bankowości internetowej. W takim przypadku tabela rejestracyjna IB może zostać użyta do ograniczenia innych tabel przed posiadaniem dalszych rekordów podrzędnych. Tutaj znowu można by to zrobić z nowym PK dla tablicy rejestracyjnej IB.
Teddy

1
@Teddy Podobnie w większości zgadzam się z tym, co powiedziałeś. Jednak w pierwotnym pytaniu stwierdzają, że „… jego rekord profilu jest tworzony automatycznie…”, co oznacza, że ​​tabela profili nie jest opcjonalna. W sytuacji, gdy tabela profili była opcjonalna, to możliwe jest posiadanie jej jako osobnej tabeli. Ale z drugiej strony mogliby po prostu użyć kolumn dopuszczających wartość null w tej samej tabeli.
Tshsmith,

1
Używając oddzielnej drugiej tabeli, możemy zapobiec wpisowi do trzeciej tabeli, co jest dozwolone tylko dla osób, które mają wpis w drugiej tabeli.
Teddy

Oczywiście, ale jeśli połączymy tabele od 1 do 1, możemy uniemożliwić osobom z wartościami null dostęp do trzeciej (teraz technicznie drugiej) tabeli. Ale pytanie zadane przez OP zawiera wiersz "... podczas rejestracji ... ... jego rekord profilu jest tworzony automatycznie ...", czyniąc to zbędnym.
Tshsmith,

Moim głównym powodem rozważenia tego jest to, że w hurtowni danych dobrą praktyką jest oddzielanie tabel faktów i tabel wymiarów. Oddzielne tabele faktów i wymiarów są przydatnymi wskazówkami podczas pracy z oprogramowaniem, takim jak PowerPivot, PowerBI i Tableau.
Marco Rosas

4

Tak, klucz obcy może być kluczem podstawowym w przypadku relacji jeden do jednego między tymi tabelami


2
jest to przydatne również przy projektowaniu podtypów nadtypów. Kluczem podstawowym tabel podtypów powinno być odniesienie klucza obcego do tabeli nadtypów.
axelioo

2

Nie zrobiłbym tego. Zachowałbym profileIDjako główny klucz tabeliProfile

Klucz obcy to po prostu ograniczenie referencyjne między dwiema tabelami

Można by argumentować, że klucz podstawowy jest niezbędny jako cel wszelkich kluczy obcych, które odnoszą się do niego z innych tabel. Klucz obcy to zestaw jednej lub więcej kolumn w dowolnej tabeli (niekoniecznie klucz kandydujący, nie mówiąc już o kluczu podstawowym tej tabeli), który może zawierać wartości znalezione w kolumnach klucza podstawowego niektórych inny stół. Musimy więc mieć klucz podstawowy pasujący do klucza obcego. A może musimy? Jedynym celem klucza podstawowego w parze klucz podstawowy / klucz obcy jest zapewnienie jednoznacznego łączenia - aby zachować integralność referencyjną w odniesieniu do „obcej” tabeli, w której znajduje się wskazany klucz podstawowy. Gwarantuje to, że wartość, do której odnosi się klucz obcy, będzie zawsze ważna (lub zerowa, jeśli jest to dozwolone).

http://www.aisintl.com/case/primary_and_foreign_key.html


1
Może - jeśli masz ograniczenie FK między User.UserID i Profile.UserID, zdecydowanie zaleca się posiadanie indeksu Profile.UserID. Dlaczego nie uczynić tego podstawowego indeksu klastrowego w profilu tabeli, oszczędzając drugi indeks i całą masę niepotrzebnej pracy dla silnika bazy danych?
Reversed Engineer

1

To zależy od firmy i systemu.

Jeśli identyfikator użytkownika jest unikalny i będzie przez cały czas unikalny, możesz użyć identyfikatora użytkownika jako klucza podstawowego. Ale jeśli kiedykolwiek zechcesz rozszerzyć swój system, utrudni to sprawę. Radzę dodać klucz obcy do użytkownika tabeli, aby nawiązać relację z profilem tabeli, zamiast dodawać klucz obcy w profilu tabeli.


0

Krótka odpowiedź: ZALEŻY… W tym konkretnym przypadku może być dobrze. Jednak eksperci będą odradzać to prawie za każdym razem; w tym twój przypadek.

Czemu?

Klucze rzadko są unikalne w tabelach, gdy są obce (pochodzące z innej tabeli) w stosunku do danej tabeli. Na przykład identyfikator pozycji może być unikatowy w tabeli ITEMS, ale nie w tabeli ORDERS, ponieważ ten sam typ pozycji najprawdopodobniej będzie istniał w innej kolejności. Podobnie, identyfikatory zamówień mogą być unikalne (mogą) w tabeli ORDERS, ale nie w innej tabeli, takiej jak ORDER_DETAILS, w której może istnieć zamówienie z wieloma elementami zamówienia, a aby wykonać zapytanie dotyczące konkretnego elementu w określonej kolejności, potrzebujesz połączenia dwóch FK (order_id i item_id) jako PK dla tej tabeli.

Nie jestem ekspertem od DB, ale jeśli możesz logicznie uzasadnić posiadanie automatycznie generowanej wartości jako twojego PK, zrobiłbym to. Jeśli to nie jest praktyczne, to połączenie dwóch (lub może więcej) FK może służyć jako twoja PK. ALE nie przychodzi mi do głowy żaden przypadek, w którym pojedyncza wartość FK może być uzasadniona jako PK.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.