Czy mogę mieć wiele kluczy podstawowych w jednej tabeli?


Odpowiedzi:


559

Tabela może mieć złożony klucz podstawowy, który jest kluczem podstawowym złożonym z dwóch lub więcej kolumn. Na przykład:

CREATE TABLE userdata (
  userid INT,
  userdataid INT,
  info char(200),
  primary key (userid, userdataid)
);

Aktualizacja: Oto link z bardziej szczegółowym opisem złożonych kluczy podstawowych.


2
W tym przykładzie BOTH userid i userdataid są potrzebne do zidentyfikowania / znalezienia unikalnego wiersza. Nie jestem pewien, co zamierzał OP, ale przyszedłem tutaj, aby sprawdzić, czy potrafię jednoznacznie zidentyfikować wiersz za pomocą jednego z zestawu kluczy. Na przykład chciałbym zidentyfikować unikalnego użytkownika za pomocą nazwy użytkownika LUB identyfikatora użytkownika, bez potrzeby korzystania z obu. Wydaje mi się, że odpowiedź RB na unikalne indeksy załatwi sprawę.
Burrito,

1
@Benitok Jak wspomniano w RB. Na odpowiedź , można użyć unikalnych indeksów do tego, co szukasz (wyjątkowej, indeksowanej kolumnie niezależny od innych unikalnych indeksowanych kolumnach w tej samej tabeli). Aby uzyskać szczegółowe informacje na temat używanej składni języka, zapoznaj się z instrukcją obsługi podręcznika SQL.
rano

195

Możesz mieć tylko jeden klucz podstawowy, ale możesz mieć wiele kolumn w kluczu podstawowym.

Możesz także mieć unikalne indeksy na swoim stole, które będą działać trochę jak klucz podstawowy, ponieważ będą wymuszały unikalne wartości i przyspieszą zapytania o te wartości.


39

Tabela może mieć wiele kluczy kandydujących. Każdy klucz kandydujący jest kolumną lub zestawem kolumn, które są UNIKALNE, wzięte razem, a także NIE NULL. Zatem określenie wartości dla wszystkich kolumn dowolnego klucza kandydującego wystarczy, aby stwierdzić, że jest jeden wiersz spełniający kryteria lub w ogóle nie ma wierszy.

Klucze kandydujące są podstawową koncepcją w relacyjnym modelu danych.

Powszechną praktyką jest, jeśli w jednej tabeli znajduje się wiele kluczy, aby wyznaczyć jeden z kluczy kandydujących jako klucz podstawowy. Powszechną praktyką jest również powodowanie, że wszelkie klucze obce do tabeli odnoszą się do klucza podstawowego, a nie do dowolnego innego klucza kandydującego.

Polecam te praktyki, ale w modelu relacyjnym nie ma niczego, co wymagałoby wybrania klucza podstawowego spośród kluczy kandydujących.


5
Zgoda. Wszystkie klucze są równe (żaden nie jest „podstawowy”) w modelu logicznym. Wybór, który klucz w fizycznej implementacji ma otrzymać KLUCZ PODSTAWOWY, zależy od arbitrażu i dostawcy / produktu.
poniedziałek

3
Powiedziałbym, że to zależy od projektanta bazy danych.
Walter Mitty,

Właśnie natrafiłem na przypadek użycia, w którym jest to wymagane. Mam tabelę, która zostanie utworzona / zarządzana przez Entity Framework - która, o ile mogę zebrać, nie obsługuje obecnie unikalnych ograniczeń kompozytowych innych niż klucz podstawowy. Jednak obsługuje złożone klucze podstawowe. Dane zostaną również połączone ze zdalnym systemem bazy danych, który w ogóle nie obsługuje kluczy kompozytowych. Poszedłem do tworzenia Composite PK w EF, ale także dodawania niepozwalającej na kolumnę identyfikatora GUID, którego drugi system może użyć do jednoznacznej identyfikacji.
Chris Nevill

2
Chris, powiedziałem, że model relacyjny nie wymaga kluczy podstawowych. Nie powiedziałem nic o tym, czy jakieś narzędzie może ich wymagać. Ale rozumiem twój punkt widzenia.
Walter Mitty

Myślę, że istnieje wymóg, aby PK był minimalny, tzn. Używa najmniejszej liczby kolumn do jednoznacznej identyfikacji każdego rekordu.
Gary

14

To jest odpowiedź zarówno na główne pytanie, jak i na pytanie @ Kalmi

Jaki byłby sens posiadania wielu automatycznie generujących kolumn?

Poniższy kod ma złożony klucz podstawowy. Jedna z jej kolumn jest automatycznie zwiększana. Działa to tylko w MyISAM. InnoDB wygeneruje błąd „ BŁĄD 1075 (42000): Niepoprawna definicja tabeli; może istnieć tylko jedna kolumna automatyczna i należy ją zdefiniować jako klucz ”.

DROP TABLE IF EXISTS `test`.`animals`;
CREATE TABLE  `test`.`animals` (
  `grp` char(30) NOT NULL,
  `id` mediumint(9) NOT NULL AUTO_INCREMENT,
  `name` char(30) NOT NULL,
  PRIMARY KEY (`grp`,`id`)
) ENGINE=MyISAM;

INSERT INTO animals (grp,name) VALUES
    ('mammal','dog'),('mammal','cat'),
    ('bird','penguin'),('fish','lax'),('mammal','whale'),
    ('bird','ostrich');

SELECT * FROM animals ORDER BY grp,id;

Which returns:

+--------+----+---------+
| grp    | id | name    |
+--------+----+---------+
| fish   |  1 | lax     |
| mammal |  1 | dog     |
| mammal |  2 | cat     |
| mammal |  3 | whale   |
| bird   |  1 | penguin |
| bird   |  2 | ostrich |
+--------+----+---------+

2
Działa to, jeśli najpierw określisz kolumnę automatycznego zwiększania w definicji klucza podstawowego. (Może to się zmieniło, właśnie przetestowałem to w 5.6)
CTarczon

11

(Dużo ich studiowałem)

Klucze kandydujące - minimalna kombinacja kolumn wymagana do jednoznacznej identyfikacji wiersza tabeli.
Klucze złożone - 2 lub więcej kolumn.

  • W tabeli może istnieć wiele kluczy kandydujących .
    • Klucz główny - tylko jeden z wybranych przez nas kluczy kandydujących
    • Alternatywne klucze - Wszystkie pozostałe klucze kandydujące
      • Zarówno klucz główny, jak i klucze alternatywne mogą być kluczami złożonymi

Źródła:
https://en.wikipedia.org/wiki/Superkey
https://en.wikipedia.org/wiki/Candidate_key
https://en.wikipedia.org/wiki/Primary_key
https://en.wikipedia.org / wiki / Compound_key


6

Jak zauważyli inni, możliwe jest posiadanie kluczy głównych z wieloma kolumnami. Należy jednak zauważyć, że jeśli masz pewne zależności funkcjonalne , które nie są wprowadzane przez klucz, powinieneś rozważyć normalizację swojej relacji.

Przykład:

Person(id, name, email, street, zip_code, area)

Może istnieć zależność funkcjonalna między, id -> name,email, street, zip_code and area ale często a zip_codejest powiązana z a, areaa zatem istnieje wewnętrzna zależność funkcjonalna między zip_code -> area.

Dlatego można rozważyć podzielenie go na inną tabelę:

Person(id, name, email, street, zip_code)
Area(zip_code, name)

Aby był zgodny z trzecią normalną formą .


6

Klucz podstawowy jest bardzo niefortunnym zapisem ze względu na konotację „Pierwotnego” i podświadomego skojarzenia z modelem logicznym. W ten sposób unikam jego używania. Zamiast tego mówię o kluczu zastępczym modelu fizycznego i kluczu naturalnego modelu logicznego.

Ważne jest, aby model logiczny dla każdej jednostki miał co najmniej jeden zestaw „atrybutów biznesowych”, które składają się na klucz dla encji. Boyce, Codd, Date i in. Określają je w modelu relacyjnym jako klucze kandydujące. Kiedy następnie budujemy tabele dla tych jednostek, ich klucze kandydujące stają się kluczami naturalnymi w tych tabelach. Tylko dzięki tym kluczom naturalnym użytkownicy mogą jednoznacznie identyfikować wiersze w tabelach; ponieważ klucze zastępcze powinny zawsze być ukryte przed użytkownikami. Wynika to z tego, że klucze zastępcze nie mają znaczenia biznesowego.

Jednak model fizyczny dla naszych tabel będzie w wielu przypadkach nieefektywny bez klucza zastępczego. Przypomnij sobie, że nieobjęte kolumny dla indeksu nieklastrowego można znaleźć (ogólnie) poprzez wyszukiwanie klucza w indeksie klastrowym (przez chwilę ignoruj ​​tabele zaimplementowane jako stosy). Kiedy nasze dostępne Klucze Naturalne są szerokie, to (1) poszerza szerokość naszych nieklastrowych węzłów liści, zwiększając wymagania dotyczące przechowywania i dostęp do odczytu dla wyszukiwań i skanów tego nieklastrowanego indeksu; oraz (2) zmniejsza rozrzut z naszego indeksu klastrowego, zwiększając wysokość indeksu i jego rozmiar, ponownie zwiększając wymagania dotyczące odczytu i przechowywania naszych indeksów klastrowych; oraz (3) zwiększa wymagania pamięci podręcznej dla naszych indeksów klastrowych. wypędzanie innych indeksów i danych z pamięci podręcznej.

W tym przypadku korzystny jest mały klucz zastępczy, oznaczony jako RDBMS jako „klucz podstawowy”. Po ustawieniu jako klucz klastrowania, aby można go było używać do wyszukiwania kluczy w indeksie klastrowym z indeksów nieklastrowanych i wyszukiwania kluczy obcych z powiązanych tabel, wszystkie te wady znikają. Nasze rozkładania indeksów klastrowych ponownie zwiększają się, aby zmniejszyć wysokość i rozmiar indeksów klastrowych, zmniejszyć obciążenie pamięci podręcznej dla naszych indeksów klastrowanych, zmniejszyć odczyty podczas uzyskiwania dostępu do danych za pomocą dowolnego mechanizmu (czy to skanowania indeksu, wyszukiwania indeksu, wyszukiwania klucza nieklastrowanego lub klucza obcego) i zmniejsz wymagania dotyczące miejsca dla indeksów klastrowych i nieklastrowanych naszych tabel.

Należy zauważyć, że korzyści te występują tylko wtedy, gdy klucz zastępczy jest zarówno mały, jak i klucz klastrowania. Jeśli GUID jest używany jako klucz klastrowania, sytuacja często będzie gorsza niż w przypadku użycia najmniejszego dostępnego klucza naturalnego. Jeśli tabela jest zorganizowana jako sterta, wówczas 8-bajtowa (sterta) RowID będzie używana do wyszukiwania kluczy, co jest lepsze niż 16-bajtowy GUID, ale mniej wydajny niż 4-bajtowa liczba całkowita.

Jeśli z powodu ograniczeń biznesowych należy użyć identyfikatora GUID, warto poszukać lepszego klucza klastrowania. Jeśli na przykład wykonalny jest mały identyfikator witryny i 4-bajtowy „numer sekwencji witryny”, ten projekt może dać lepszą wydajność niż identyfikator GUID jako klucz zastępczy.

Jeśli konsekwencje stosu (być może złączenia mieszającego) powodują, że preferowane miejsce do magazynowania to koszty szerszego klucza klastrowania muszą zostać zrównoważone w analizie kompromisu.

Rozważ ten przykład:

ALTER TABLE Persons
ADD CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName)

tam, gdzie krotka „ (P_Id, LastName) ” wymaga ograniczenia unikatowości i może być długim UnicName LastName i 4-bajtową liczbą całkowitą, pożądane byłoby (1) deklaratywne wymuszenie tego ograniczenia jako „ ADD CONSTRAINT pk_PersonID UNIQUE NONCLUSTERED (P_Id , LastName) ”i (2) oddzielnie deklarują mały klucz zastępczy jako„ klucz podstawowy ”indeksu klastrowego. Warto zauważyć, że Anita prawdopodobnie chce dodać LastName do tego ograniczenia, aby uczynić to pole objęte, co nie jest konieczne w indeksie klastrowym, ponieważ WSZYSTKIE pola są nim objęte.

Zdolność SQL Server do wyznaczenia klucza podstawowego jako nieklastrowanego jest niefortunną okolicznością historyczną, ze względu na połączenie znaczenia „preferowanego klucza naturalnego lub kandydującego” (z modelu logicznego) ze znaczeniem „klucz wyszukiwania w pamięci” z fizycznego Model. Rozumiem, że pierwotnie SYBASE SQL Server zawsze używał 4-bajtowego RowID, czy to w stercie, czy w indeksie klastrowym, jako „klucz wyszukiwania w magazynie” z modelu fizycznego.


3
Czy możesz to przetłumaczyć na angielski!
Jasir

3

Niektóre osoby używają terminu „klucz podstawowy”, aby oznaczać dokładnie kolumnę całkowitą, której wartości są generowane przez jakiś automatyczny mechanizm. Na przykład AUTO_INCREMENTw MySQL lub IDENTITYMicrosoft SQL Server. Czy używasz klucza podstawowego w tym sensie?

Jeśli tak, odpowiedź zależy od marki używanej bazy danych. W MySQL nie możesz tego zrobić, pojawia się błąd:

mysql> create table foo (
  id int primary key auto_increment, 
  id2 int auto_increment
);
ERROR 1075 (42000): Incorrect table definition; 
there can be only one auto column and it must be defined as a key

W niektórych bazach danych innych marek możesz zdefiniować więcej niż jedną kolumnę automatycznego generowania w tabeli.


5
Jaki byłby sens posiadania wielu automatycznie generujących kolumn?
Tarnay Kálmán

Nie mam na myśli przypadku użycia, ale gdyby kiedykolwiek była taka potrzeba, niektóre marki baz danych by to wspierały, a niektóre nie. To wszystko co mówię.
Bill Karwin,

1
Oto przypadek: w tabeli rozkazów mam zarówno identyfikator (automatycznie zwiększany), jak i identyfikator zewnętrzny (ciągi przypominające hasz), oba powinny być unikalne, więc teoretycznie można powiedzieć, że oba są „podstawowe”. oczywiście można to zrobić za pomocą dodatkowego unikalnego indeksu, ale nadal jest to uzasadniony przypadek (IMHO)
Nir

2

Posiadanie dwóch kluczy podstawowych jednocześnie nie jest możliwe. Ale (zakładając, że nie pomieszałeś sprawy z kluczem złożonym), może być potrzebne, aby uczynić jeden atrybut unikalnym.

CREATE t1(
c1 int NOT NULL,
c2 int NOT NULL UNIQUE,
...,
PRIMARY KEY (c1)
);

Należy jednak pamiętać, że w relacyjnej bazie danych „superklucz” to podzbiór atrybutów, które jednoznacznie identyfikują krotkę lub wiersz w tabeli. „Klucz” to „superklucz”, który ma dodatkową właściwość polegającą na usunięciu dowolnego atrybutu z klucza, dzięki czemu ten klucz nie jest już „superkluczem” (lub po prostu „klucz” to minimalny superklucz). Jeśli jest więcej kluczy, wszystkie są kluczami kandydującymi. Wybieramy jeden z kluczy kandydujących jako klucz podstawowy. Dlatego mówienie o wielu kluczach podstawowych dla jednej relacji lub tabeli jest konfliktem.


Wikipedia nie ma definicji „klucza”. Również „usunięcie dowolnego atrybutu z klucza powoduje, że ten klucz przestaje być„ superkluczem ””, nic dla mnie nie znaczyło, ponieważ usunięcie atrybutu z superklucza może być nadal superkluczem.
Manohar Reddy Poreddy

@ManoharReddyPoreddy Tak, w takim przypadku zestaw atrybutów nie jest „kluczem”, ale „superkluczem”. Mam na myśli to, że jeśli zestaw atrybutów ma być „kluczem”, zestaw powinien być minimalny lub zestaw powinien mieć dodatkową właściwość, która po usunięciu dowolnego atrybutu ze zbioru czyni z wynikowego zestawu nie więcej „superklucz”.
Rusiru Adithya Samarasinghe

Wygląda na to, że twoje rzeczywiste znaczenie „klucza” to Candidate_key ( en.wikipedia.org/wiki/Candidate_key ), może warto o tym wspomnieć.
Manohar Reddy Poreddy

@ManoharReddyPoreddy Tak Już wspomniałem o tym w mojej odpowiedzi. „Jeśli jest więcej kluczy, wszystkie są kluczami kandydującymi”. W każdym razie dzięki za recenzję.
Rusiru Adithya Samarasinghe

1. Kiedy wspominasz „Jeśli jest więcej kluczy, wszystkie są kluczami kandydującymi”, ... Czy masz na myśli coś innego / nie są to klucze kandydujące? ... 2. Gdzie jest druga część? ... Czy w ogóle jesteśmy na tej samej stronie?
Manohar Reddy Poreddy

1

Klucz podstawowy to klucz, który jednoznacznie identyfikuje rekord i jest używany we wszystkich indeksach. Dlatego nie możesz mieć więcej niż jednego. Zasadniczo jest to również klucz używany podczas łączenia z tabelami podrzędnymi, ale nie jest to wymagane. Rzeczywistym celem PK jest upewnienie się, że coś pozwala jednoznacznie zidentyfikować rekord, aby zmiany danych wpłynęły na poprawny rekord i aby można było tworzyć indeksy.

Można jednak umieścić wiele pól w jednym kluczu podstawowym (złożonym PK). Spowoduje to spowolnienie połączeń (szczególnie jeśli są to większe pola typu łańcuchowego) i zwiększenie indeksów, ale może to wyeliminować potrzebę wykonywania połączeń w niektórych tabelach podrzędnych, jeśli chodzi o wydajność i projekt, weź to pod uwagę podstawa przypadku. Gdy to zrobisz, każde pole nie jest unikalne, ale ich kombinacja jest. Jeśli jedno lub więcej pól w kluczu złożonym również powinno być unikalne, potrzebujesz na nim unikalnego indeksu. Jest jednak prawdopodobne, że jeśli jedno pole jest unikalne, jest to lepszy kandydat na PK.

Czasami masz więcej niż jednego kandydata na PK. W takim przypadku wybierasz jeden jako PK lub używasz klucza zastępczego (osobiście wolę klucze zastępcze w tym przypadku). I (to jest krytyczne!) Dodajesz unikalne indeksy do każdego z kluczy kandydujących, które nie zostały wybrane jako PK. Jeśli dane muszą być unikalne, potrzebują unikalnego indeksu, niezależnie od tego, czy jest to PK, czy nie. Jest to problem z integralnością danych. (Uwaga: dotyczy to również każdego użycia klucza zastępczego; ludzie mają problemy z kluczami zastępczymi, ponieważ zapominają o tworzeniu unikalnych indeksów kluczy kandydujących).

Czasami potrzebujesz więcej niż jednego klucza zastępczego (którym są zwykle PK, jeśli je posiadasz). W tym przypadku nie chcesz więcej PK, to więcej pól z automatycznie generowanymi kluczami. Większość baz danych na to nie pozwala, ale istnieją sposoby na obejście tego. Najpierw zastanów się, czy drugie pole można obliczyć na podstawie pierwszego automatycznie wygenerowanego klucza (na przykład Field1 * -1), czy może potrzeba drugiego automatycznie wygenerowanego klucza naprawdę oznacza, że ​​powinieneś utworzyć powiązaną tabelę. Powiązane tabele mogą być w relacji jeden do jednego. Wymusiłbyś to, dodając PK z tabeli nadrzędnej do tabeli podrzędnej, a następnie dodając nowe automatycznie wygenerowane pole do tabeli, a następnie wszystkie pola odpowiednie dla tej tabeli. Następnie wybierz jeden z dwóch kluczy jako PK i umieść na drugim unikatowy indeks (automatycznie wygenerowane pole nie musi być PK). I pamiętaj, aby dodać FK do pola, które znajduje się w tabeli nadrzędnej. Ogólnie rzecz biorąc, jeśli nie masz dodatkowych pól tabeli potomnej, musisz sprawdzić, dlaczego uważasz, że potrzebujesz dwóch automatycznie wygenerowanych pól.


0

Dobre odpowiedzi techniczne zostały podane w lepszy sposób niż ja. Mogę tylko dodać do tego tematu:

Jeśli chcesz czegoś, co jest niedozwolone / dopuszczalne, to dobry powód, aby cofnąć się.

  1. Zrozum, dlaczego nie jest to dopuszczalne.
  2. Wykop więcej w dokumentacji / artykułach w czasopismach / Internecie itp.
  3. Przeanalizuj / przejrzyj obecny projekt i wskaż główne wady.
  4. Zastanów się i przetestuj każdy krok podczas nowego projektu.
  5. Zawsze czekaj i staraj się stworzyć rozwiązanie adaptacyjne.

Mam nadzieję, że to komuś pomoże.


1
ogólna (choć przydatna) rada, a nie odpowiedź na konkretne pytanie.
Bradford Needham

-3

Tak, jest to możliwe w SQL, ale nie możemy ustawić więcej niż jednego klucza podstawowego w MsAccess. Zatem nie wiem o innych bazach danych.

CREATE TABLE CHAPTER (
    BOOK_ISBN VARCHAR(50) NOT NULL,
    IDX INT NOT NULL,
    TITLE VARCHAR(100) NOT NULL,
    NUM_OF_PAGES INT,
    PRIMARY KEY (BOOK_ISBN, IDX)
);

Tabela SQL może mieć tylko jedną PK.
philipxy
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.