Klucz podstawowy czy unikalny indeks?

132

W pracy mamy dużą bazę danych z unikalnymi indeksami zamiast kluczy podstawowych i wszystko działa dobrze.

Projektuję nową bazę danych dla nowego projektu i mam dylemat:

W teorii DB klucz podstawowy jest elementem podstawowym, to jest OK, ale w PRAWDZIWYCH projektach jakie są zalety i wady obu?

Czego używasz w projektach?

EDYCJA: ... a co z kluczami podstawowymi i replikacją na serwerze MS SQL?

Cicik
źródło
2
Omówiono tutaj dodatkowe kwestie (aczkolwiek z dodatkowym kontekstem indeksu obejmującego) - dba.stackexchange.com/questions/21554/…
StuartLC
UWAGA: SQLite różni się tym, że zezwalają na zerową wartość klucza podstawowego, w przeciwieństwie do wspólnego standardu ze względu na problem ze starszą wersją. sqlite.org/lang_createtable.html
bitinn

Odpowiedzi:

171

Co to jest unikalny indeks?

Unikalny indeks w kolumnie to indeks w tej kolumnie, który wymusza również ograniczenie, że nie można mieć dwóch równych wartości w tej kolumnie w dwóch różnych wierszach. Przykład:

CREATE TABLE table1 (foo int, bar int);
UTWÓRZ UNIKALNY INDEKS ux_table1_foo ON table1 (foo); - Utwórz unikalny indeks na foo.

INSERT INTO table1 (foo, bar) VALUES (1, 2); -- OK
INSERT INTO table1 (foo, bar) VALUES (2, 2); -- OK
INSERT INTO table1 (foo, bar) VALUES (3, 1); -- OK
INSERT INTO table1 (foo, bar) VALUES (1, 4); - Zawodzi!

Zduplikowany wpis „1” dla klucza „ux_table1_foo”

Ostatnia operacja wstawiania kończy się niepowodzeniem, ponieważ narusza unikalny indeks w kolumnie, foogdy próbuje wstawić wartość 1 do tej kolumny po raz drugi.

W MySQL unikalne ograniczenie zezwala na wiele wartości NULL.

Możliwe jest utworzenie unikalnego indeksu na wielu kolumnach.

Klucz podstawowy a unikalny indeks

Rzeczy, które są takie same:

  • Klucz podstawowy oznacza unikalny indeks.

Różne rzeczy:

  • Klucz podstawowy również implikuje NOT NULL, ale unikalny indeks może mieć wartość null.
  • Może istnieć tylko jeden klucz podstawowy, ale może istnieć wiele unikalnych indeksów.
  • Jeśli nie zdefiniowano indeksu klastrowego, kluczem podstawowym będzie indeks klastrowy.
Mark Byers
źródło
4
Należy zauważyć, że unikalny indeks to indeks kolumny nie jest całkowicie dokładny, ponieważ jeden unikalny indeks lub klucz podstawowy może zawierać więcej niż jedną kolumnę.
Alex Jasmin
2
@Alexandre Jasmin: Naprawiono dzięki. Część dotycząca wielu kolumn zostanie wspomniana później.
Mark Byers
W odniesieniu do wartości null, standardy ansi dopuszczają wiele wartości null w zestawie danych z unikalnym ograniczeniem i jest to również implementacja w Oracle i PostgreSQL. Uważam, że SQL Server dopuszcza tylko jedną wartość zerową.
David Aldridge,
3
ale nadal go nie rozumiem, kiedy używać klucza podstawowego, a kiedy unikalnego indeksu? lub mogą być oboje w tych samych sytuacjach.
Amit
34

Możesz to zobaczyć w ten sposób:

Klucz podstawowy JEST wyjątkowy

Unikalna wartość nie musi być reprezentacją elementu

Znaczenie?; Cóż, klucz podstawowy jest używany do identyfikacji elementu, jeśli masz „Osobę”, chciałbyś mieć osobisty numer identyfikacyjny (SSN lub inny), który jest nadrzędny dla Twojej osoby.

Z drugiej strony, osoba może mieć adres e-mail, który jest unikalny, ale nie identyfikuje osoby.

Zawsze mam klucze podstawowe, nawet w tabelach relacji (tabela środkowa / tabela połączeń), które mogę mieć. Czemu? Cóż, lubię kierować się standardem podczas kodowania, jeśli "Osoba" ma identyfikator, Samochód ma identyfikator, cóż, Osoba -> Samochód również powinien mieć identyfikator!

Filip Ekberg
źródło
W tabelach relacji: czy masz na myśli, że wprowadzasz nową kolumnę ze sztucznym kluczem podstawowym (na przykład liczbą całkowitą), czy też używasz złożonego klucza podstawowego (person_id, car_id)?
3
klucz podstawowy (person_id, car_id) byłby najlepszy. Ale generalnie tworzę nową kolumnę, na pewno daje trochę narzutów, ale uznałem, że jest dobra. Nigdy nie wiesz, czy chcesz odnieść się do określonej relacji w późniejszym scenariuszu.
Filip Ekberg
1
Inną rzeczą, jaką zastępuje zastępczy klucz podstawowy dla tabeli złożonej / złączonej, jest łatwość obsługi zadań ręcznych.
Robert C. Barth
2
Klucz podstawowy potrzebujesz tylko, jeśli zamierzasz mieć dzieci. Po co dodawać kolumnę i sekwencję, jeśli wartość nie pojawia się nigdzie, jeśli wartość jest używana do niczego? To działa, aby uniemożliwić Accessowi proszenie o PK. Zrób PK, jeśli chcesz zidentyfikować rekord u dziecka, w przeciwnym razie jest to strata.
3
Jeśli nie ma to nic wspólnego z relacjami, co to ma wspólnego? Wskazujesz na pole i mówisz, że to podstawowe. I? Więc co się dzieje? A jeśli nie ma naturalnego pk, dodaję kolumnę i sekwencję oraz wyzwalacz i wszystko dlatego, że ____? Niektórzy po prostu muszą być Podstawowymi. Unikam zasad bez powodu.
10

Klucze obce działają z unikatowymi ograniczeniami, a także z kluczami podstawowymi. Z Books Online:

Ograniczenie FOREIGN KEY nie musi być połączone tylko z ograniczeniem PRIMARY KEY w innej tabeli; można go również zdefiniować tak, aby odwoływał się do kolumn ograniczenia UNIQUE w innej tabeli

Do replikacji transakcyjnej potrzebny jest klucz podstawowy. Z Books Online:

Tabele publikowane do replikacji transakcyjnej muszą mieć klucz podstawowy. Jeśli tabela znajduje się w publikacji replikacji transakcyjnej, nie można wyłączyć żadnych indeksów skojarzonych z kolumnami klucza podstawowego. Te indeksy są wymagane przez replikację. Aby wyłączyć indeks, musisz najpierw usunąć tabelę z publikacji.

Obie odpowiedzi dotyczą programu SQL Server 2005.

Jonas Lincoln
źródło
TO mnie piekielnie przeraża (pierwszy cytat). Czemu? Mam stół osoby z dowolnym identyfikatorem, który jest moim PK, ale decyduję się dodać Wielką Brytanię do telefonu, e-maila i numeru PESEL ... więc teraz 4 różne tabele dołączają do osoby w 4 różnych kolumnach? Myślę, że zrezygnowałbym z jakiejkolwiek elastyczności, jaką można uzyskać dla spójności.
5

Wybór, kiedy użyć zastępczego klucza podstawowego, a kiedy klucza naturalnego, jest trudny. Odpowiedzi typu „zawsze lub nigdy” rzadko są przydatne. Uważam, że to zależy od sytuacji.

Jako przykład mam następujące tabele:

CREATE TABLE toll_booths (
    id            INTEGER       NOT NULL PRIMARY KEY,
    name          VARCHAR(255)  NOT NULL,
    ...
    UNIQUE(name)
)

CREATE TABLE cars (
    vin           VARCHAR(17)   NOT NULL PRIMARY KEY,
    license_plate VARCHAR(10)   NOT NULL,
    ...
    UNIQUE(license_plate)
)

CREATE TABLE drive_through (
    id            INTEGER       NOT NULL PRIMARY KEY,
    toll_booth_id INTEGER       NOT NULL REFERENCES toll_booths(id),
    vin           VARCHAR(17)   NOT NULL REFERENCES cars(vin),
    at            TIMESTAMP     DEFAULT CURRENT_TIMESTAMP NOT NULL,
    amount        NUMERIC(10,4) NOT NULL,
    ...
    UNIQUE(toll_booth_id, vin)
)

Mamy dwie tabele encji ( toll_boothsi cars) oraz tabelę transakcji ( drive_through). toll_boothTabela używa klucza zastępczego, ponieważ ma naturalny atrybut, który nie jest gwarantowana do zmian (nazwa może być łatwo zmieniona). carsTabela wykorzystuje naturalne klucz podstawowy, ponieważ ma non zmieniających unikalny identyfikator ( vin). drive_throughStół transakcja używa klucza zastępczego dla łatwej identyfikacji, ale ma również wyjątkową presję na atrybutach, które są gwarantowane, aby być unikatowa w momencie rekord jest włożona.

http://database-programmer.blogspot.com zawiera świetne artykuły na ten temat.

aekeus
źródło
4

Klucze podstawowe nie mają wad.

Aby dodać tylko trochę informacji do odpowiedzi @MrWiggles i @Peter Parker, gdy tabela nie ma klucza podstawowego, na przykład nie będziesz mógł edytować danych w niektórych aplikacjach (w końcu powiedzą coś takiego jak nie można edytować / usuwać danych bez klucz podstawowy). Postgresql zezwala na umieszczanie wielu wartości NULL w kolumnie UNIQUE, klucz PRIMARY KEY nie zezwala na wartości NULL. Również niektóre ORM, które generują kod, mogą mieć problemy z tabelami bez kluczy podstawowych.

AKTUALIZACJA:

O ile wiem, nie jest możliwa replikacja tabel bez kluczy podstawowych w MSSQL, przynajmniej bez problemów ( szczegóły ).

empi
źródło
Podczas wstawiania nowych wierszy lub aktualizacji kolumny występuje narzut.
3

Jeśli coś jest kluczem podstawowym, w zależności od silnika bazy danych, cała tabela jest sortowana według klucza podstawowego. Oznacza to, że wyszukiwania są znacznie szybsze w przypadku klucza podstawowego, ponieważ nie musi wykonywać żadnych wyłuskiwania, jak ma to miejsce w przypadku każdego innego rodzaju indeksu. Poza tym to tylko teoria.

Ray Hidayat
źródło
3
tabela zostanie posortowana według indeksu klastrowego, niekoniecznie według klucza podstawowego.
Ray Booysen
1
tak się składa, że ​​większość ludzi ustawia klucz podstawowy jako indeks klastrowy.
Ray Booysen
Co, jak wiemy, jest często naprawdę złym pomysłem, chyba że lubimy gorące punkty i niezrównoważone drzewa indeksowe w naszych tabelach, oczywiście ...
Mike Woodhouse
1
To nie ZAWSZE naprawdę zły pomysł. Poznaj swoje dane, poznaj RDBMS, dowiedz się, co oznaczają wybory. Rzadko kiedy wybór jest ZAWSZE dobry lub zły. Gdyby było ZAWSZE, baza danych wymagałaby tego lub zabroniła. Dają ci wybór, ponieważ „to zależy”.
2

Oprócz tego, co powiedziały inne odpowiedzi, niektóre bazy danych i systemy mogą wymagać obecności podstawowego. Przychodzi mi na myśl jedna sytuacja; podczas korzystania z replikacji korporacyjnej z produktem Informix, aby tabela uczestniczyła w replikacji, musi być obecny PK.

tddmonkey
źródło
2

Dopóki nie zezwalasz na NULL dla wartości, powinny być traktowane tak samo, ale wartość NULL jest obsługiwana inaczej w bazach danych (AFAIK MS-SQL nie zezwala na więcej niż jedną (1) wartość NULL, mySQL i Oracle pozwalają na to , jeśli kolumna jest UNIQUE), więc musisz zdefiniować tę kolumnę NOT NULL UNIQUE INDEX

Peter Parker
źródło
1
MS-SQL dopuszcza wiele wartości NULL w kolumnie, która ma unikalny indeks, podobnie jak każdy RDBMS. Pomyśl o tym w ten sposób: NULL nie jest wartością, więc kiedy wstawisz drugi NULL, nigdy nie będzie pasował do istniejącej. Wyrażenie (NULL == NULL) nie jest ewaluowane do true lub false, zwraca wartość NULL.
gregmac
thanx gregmac, nie byłem pewien, czy stwardnienie rozsiane podąża za tym. Przypomniałem sobie z tym kilka MS Quirks, jednak kilka lat temu (przed 2000 rokiem) i mógł to być również stary kaszel
Peter Parker
2

W relacyjnej teorii danych nie ma czegoś takiego jak klucz podstawowy, więc na twoje pytanie należy odpowiedzieć na poziomie praktycznym.

Unikalne indeksy nie są częścią standardu SQL. Konkretna implementacja DBMS określi konsekwencje zadeklarowania unikalnego indeksu.

W Oracle zadeklarowanie klucza podstawowego spowoduje utworzenie w Twoim imieniu unikalnego indeksu, więc pytanie jest prawie dyskusyjne. Nie mogę ci powiedzieć o innych produktach DBMS.

Preferuję zadeklarowanie klucza podstawowego. Skutkuje to zakazem stosowania wartości NULL w kolumnach klucza, a także zakazu tworzenia duplikatów. Opowiadam się również za deklarowaniem ograniczeń REFERENCJI w celu wymuszenia integralności jednostki. W wielu przypadkach zadeklarowanie indeksu w coulmn (ach) klucza obcego przyspieszy łączenie. Ten rodzaj indeksu na ogół nie powinien być unikalny.

Walter Mitty
źródło
Klucz podstawowy w MS SQL Server jest zawsze UNIQUE i NOT NULL - np. Jest to tak naprawdę tylko unikalny indeks, ale z dodatkowym ograniczeniem, że nie może być NULL.
marc_s
Oracle może wymusić Unikalne Ograniczenie z nieunikalnym indeksem. Byłbym zdziwiony, gdyby MSSS nie mógł. Mówienie „to naprawdę tylko unikalny indeks” to krzywda.
„W wielu przypadkach zadeklarowanie indeksu w coulmn (ach) klucza obcego przyspieszy łączenie”. prawie zawsze nie jest to prawdą w świecie hurtowni danych, w którym preferowane byłoby łączenie skrótów, jeśli jest dostępne.
JAC2703
OP nie wspomniał o magazynach. Nie jestem pewien, jak działa funkcja hash loins na serwerze sql. Ile pracy można wykonać w czasie aktualizacji magazynu.
Walter Mitty
2

Istnieją pewne wady INDEKSÓW KLASTEROWANYCH w porównaniu z INDEKSAMI UNIQUE.

Jak już wspomniano, KLUSTEROWANY INDEKS fizycznie porządkuje dane w tabeli.

Oznacza to, że jeśli masz dużo wstawiania lub usuwania w tabeli zawierającej indeks klastrowy, za każdym razem (no prawie, w zależności od współczynnika wypełnienia) zmieniasz dane, fizyczna tabela musi zostać zaktualizowana, aby pozostać posortowana.

W przypadku stosunkowo małych tabel jest to w porządku, ale podczas uzyskiwania dostępu do tabel, które mają dane o wartości GB, a wstawianie / usuwanie wpływa na sortowanie, napotkasz problemy.

Nico Bester
źródło
Jaka jest zatem korzyść? posortowane zapytania są szybsze? Czy jest to lepsze w przypadku użycia, gdy większość danych zapisujesz raz (lub rzadko) i cały czas wysyłasz do nich zapytania?
Buffalo
1

Prawie nigdy nie tworzę tabeli bez numerycznego klucza podstawowego. Jeśli istnieje również naturalny klucz, który powinien być unikalny, umieszczam na nim również unikalny indeks. Łączenia są szybsze w przypadku liczb całkowitych niż klucze naturalne w wielu kolumnach, dane muszą zmieniać się tylko w jednym miejscu (klucze naturalne zwykle wymagają aktualizacji, co jest złe, gdy znajdują się w relacjach klucz podstawowy - klucz obcy). Jeśli będziesz potrzebować replikacji, użyj identyfikatora GUID zamiast liczby całkowitej, ale w większości przypadków wolę klucz, który jest czytelny dla użytkownika, zwłaszcza jeśli muszą go zobaczyć, aby odróżnić John Smith od John Smith.

Kilka razy nie tworzę zastępczego klucza, gdy mam stół łączący, który jest zaangażowany w relację wiele do wielu. W tym przypadku deklaruję oba pola jako klucz podstawowy.

HLGEM
źródło
„Prawie nigdy nie tworzę tabeli bez numerycznego klucza podstawowego”: dlaczego zawsze numeryczny? Klucz podstawowy nie musi być numeryczny (nie musi też być AUTO_INCREMENT).
Hibou57
@ Hinou57, ponieważ odkryłem, że naturalne klucze rzadko są unikalne i prawie zawsze można je zmieniać. Dalej łączenia na intergerach są generalnie znacznie szybsze niż łączenia na naturalnych kluczach varcahrr lub gorszych kluczach złożonych. Nie używałbym ich przez większość czasu. Może się to różnić w zależności od rodzaju informacji, które przechowujesz w swojej bazie danych, ale z moich osobistych doświadczeń wynika, że ​​naturalne klucze są niezwykle niewiarygodne w czasie.
HLGEM
Dzięki za odpowiedź HLGEM. Co masz na myśli mówiąc niewiarygodnie? Występ? (Mam nadzieję, że to nie jest kwestia wiarygodności w sensie integralności danych). Jestem trochę zaskoczony twoimi słowami, ponieważ myślałem, że używanie kluczy całkowitych lub bardziej naturalnych kluczy, takich jak krótki VARCHAR, prawdopodobnie zrobiłoby niewielką różnicę, ponieważ haszowanie jest używane wszędzie, nawet w najprostszych silnikach DB.
Hibou57
Są niewiarygodne w wielu przypadkach, ponieważ nie są niezawodnie unikalne, mimo że powinny być. Są niewiarygodne, ponieważ się zmieniają i mogą mieć wpływ na miliony rekordów w uopdate. To jest moje doświadczenie, gdy widziałem i zarządzałem danymi lub pobierałem dane z setek baz danych, które przechowują dane o wielu różnych typach informacji, lub importowałem je z setek baz danych.
HLGEM,
1

Rozumiem, że klucz podstawowy i unikalny indeks z ograniczeniem niezerowym są takie same (*); i przypuszczam, że jeden wybiera jedną lub drugą w zależności od tego, co wyraźnie stwierdza lub sugeruje specyfikacja (kwestia tego, co chcesz wyrazić i wyraźnie egzekwować). Jeśli wymaga unikalności i nie jest zerowy, uczyń go kluczem podstawowym. Jeśli po prostu się zdarzy, że wszystkie części unikatowego indeksu nie są zerowe bez żadnego wymagania, po prostu uczyń go unikalnym indeksem.

Jedyną pozostałą różnicą jest to, że możesz mieć wiele niepowtarzalnych indeksów niezerowych, podczas gdy nie możesz mieć wielu kluczy podstawowych.

(*) Z wyjątkiem praktycznej różnicy: klucz podstawowy może być domyślnym kluczem unikalnym dla niektórych operacji, takich jak definiowanie klucza obcego. Dawny. jeśli zdefiniowano klucz obcy odwołujący się do tabeli i nie podano nazwy kolumny, jeśli tabela, do której istnieje odniesienie, ma klucz podstawowy, wówczas kluczem podstawowym będzie kolumna, do której się odwołuje. W przeciwnym razie kolumna, do której istnieje odwołanie, będzie musiała zostać jawnie nazwana.

Inni tutaj wspominali o replikacji DB, ale ja o tym nie wiem.

Hibou57
źródło
0

Unikalny indeks może mieć jedną wartość NULL. Tworzy INDEKS BEZ KLASTERÓW. Klucz podstawowy nie może zawierać wartości NULL. Tworzy CLUSTERED INDEX.

Chirag
źródło
0

W MSSQL klucze podstawowe powinny rosnąć monotonicznie, aby uzyskać najlepszą wydajność w indeksie klastrowym. Dlatego liczba całkowita z wstawką tożsamości jest lepsza niż jakikolwiek naturalny klucz, który może nie rosnąć monotonicznie.

Markus
źródło
-1

Jeżeli to zależałoby ode mnie...

Musisz spełniać wymagania bazy danych i aplikacji.

Dodanie automatycznie zwiększającej się liczby całkowitej lub kolumny o długim identyfikatorze do każdej tabeli, która służy jako klucz podstawowy, spełnia wymagania bazy danych.

Następnie należy dodać co najmniej jeden inny unikalny indeks do tabeli, który będzie używany przez aplikację. Byłby to indeks na identyfikator_pracownika, identyfikator_konta lub identyfikator_klienta itp. Jeśli to możliwe, indeks ten nie powinien być indeksem złożonym.

Wolałbym indeksy na kilku polach indywidualnie w stosunku do indeksów złożonych. Baza danych będzie używać indeksów pojedynczego pola za każdym razem, gdy klauzula where zawiera te pola, ale użyje złożonego tylko wtedy, gdy podasz pola w dokładnie prawidłowej kolejności - co oznacza, że ​​nie może użyć drugiego pola w indeksie złożonym, chyba że podasz zarówno pierwszą, jak i drugą w klauzuli where.

Jestem za korzystaniem z indeksów obliczanych lub typu funkcji - i polecam używanie ich zamiast indeksów złożonych. Ułatwia to używanie indeksu funkcji, używając tej samej funkcji w klauzuli where.

To zadba o wymagania aplikacji.

Jest wysoce prawdopodobne, że inne indeksy inne niż podstawowe są w rzeczywistości odwzorowaniami wartości klucza indeksów na wartość klucza podstawowego, a nie rowid (). Pozwala to na fizyczne sortowanie i usuwanie bez konieczności ponownego tworzenia tych indeksów.

Rodney P. Barbati
źródło