Udostępniasz jedną sekwencję klucza głównego w bazie danych?

14

Czy dopuszczalną praktyką jest stosowanie pojedynczej sekwencji jako klucza podstawowego we wszystkich tabelach (zamiast tego, że klucz podstawowy jest unikalny dla danej tabeli, jest unikalny dla wszystkich tabel)? Jeśli tak, to czy jest to obiektywnie lepsze niż stosowanie pojedynczej sekwencji klucza głównego między tabelami.

Jestem młodszym programistą, a nie DBA, więc wciąż uczę się wielu podstaw dobrego projektowania baz danych.

Edycja: na wypadek, gdyby ktoś się zastanawiał, niedawno przeczytałem krytykę projektu bazy danych autorstwa jednego z DBA naszej firmy, który wspomniał, że problem polega na tym, że projekt nie używał jednego klucza podstawowego w całej bazie danych, który brzmiał inaczej niż Nauczyłem się do tej pory.

Edycja2: Aby odpowiedzieć na pytanie w komentarzach, dotyczy to Oracle 11g, ale zastanawiałem się na poziomie innym niż baza danych. Jeśli to pytanie zależy od bazy danych, chciałbym wiedzieć, dlaczego, ale w takim przypadku szukałbym odpowiedzi specyficznej dla Oracle.

Lawtonfogle
źródło
2
Jest to zazwyczaj okropny pomysł ze względu na wydajność.
Philᵀᴹ
1
W rzeczywistości istnieje silniejsza korzyść z posiadania każdej tabeli z własnym, niezależnym zakresem klucza głównego. Ale tylko w tym przypadku, gdy spojrzysz na kilka identyfikatorów, możesz powiedzieć, że to Konta, to jest PurchaseHeader itp. Wykonanie tego wymaga pewnej konfiguracji i (jak każda rzecz specjalnego przeznaczenia) ciągłej opieki i karmienia. (Tak, pracowałem z takim systemem wiele lat temu.)
RLF
Z którego DBMS korzystasz? Wyrocznia? Postgres? DB2?
a_horse_w_no_name
1
Czy to możliwe, że źle zrozumiałeś, co miał na myśli? Może nie był taki dosłowny?
JamesRyan
Czy firma DBA faktycznie oznaczała, że ​​w żadnej z tabel nie ma pól klucza podstawowego?
Max Vernon

Odpowiedzi:

13

Do przyjęcia? Pewnie. Wspólny? Nie. Korzystne? Wątpliwy.

W mojej starej pracy odziedziczyliśmy system, w którym mieli centralny generator sekwencji (był to system SQL Server na długo przed SEQUENCEwprowadzeniem go w SQL Server 2012). To nie było tak naprawdę wąskie gardło wydajności i nie powinno tak być, chyba że generujesz setki tysięcy wartości na sekundę. Ale sprawiło, że cały kod był o wiele bardziej skomplikowany, niż musiał być, bez uzasadnionego powodu. Zamiarem projektu było upewnienie się, że jeśli coś w systemie ma przypisaną wartość identyfikatora 12, tylko jedna rzecz w systemie może mieć identyfikator 12. Wydawało mi się to dość tępe i nigdy tego nie rozumiałem. Jeśli mam klienta o identyfikatorze klienta = 12, dlaczego to uniemożliwia mi zamówienie o numerze identyfikacyjnym klienta = 12?

Widzę przydatność centralnego generatora sekwencji, jeśli masz wiele systemów i generujesz identyfikatory dla określonego rodzaju bytu (powiedzmy, klienta lub zamówienia) z tych wielu systemów. Centralna sekwencja może dawać nowe wartości wielu systemom, nie będąc wąskim gardłem (tylko jednym punktem awarii) i bez obawy, że dwa systemy wygenerują ten sam identyfikator.

Aaron Bertrand
źródło
Gdybyś musiał wybierać między czymś takim a używaniem unikalnych identyfikatorów jako kluczy głównych, czy miałbyś preferencje (choć odpowiedź prawdopodobnie brzmi „zależy”)? Wygląda na to, że GUID rozwiązałby problem w ten sam sposób, z tym wyjątkiem, że uzyskałbyś standardową implementację zamiast konieczności uruchamiania własnego scentralizowanego generatora klucza podstawowego. Oczywiście użycie sekwencji w SQL 2012 osiągnęłoby obie rzeczy, ale zakładając, że ktoś korzysta ze starszej wersji?
SqlRyan
2
@SqlRyan Muszę zrozumieć, dlaczego identyfikator zamówienia musi być całkowicie różny od identyfikatora klienta. Niemal na pewno nie użyłbym do tego GUID; konfiguracja zakresów TOŻSAMOŚCI może być lepsza (klienci zaczynają się od 1, zamówienia zaczynają się od 1000000 itd.) z alertami, gdy zbliżasz się do wyczerpania zakresu.
Aaron Bertrand
1
@SqlRyan - użycie źle zaimplementowanego identyfikatora GUID jako klastrowego klucza podstawowego może powodować różnego rodzaju problemy. Jak powiedział Aaron, TOŻSAMOŚĆ znacznie lepiej pasuje do celu.
Max Vernon
W poprzednim systemie widziałem stosowanie pojedynczej sekwencji w całej bazie danych, aby to zrobić, aby klucz obcy wskazywał wiele różnych tabel zamiast jednej tabeli, więc kiedy powiedziałeś, że klucz obcy z dwóch różnych wierszy mieli 12 lat, wiedzieliście, że wskazywali na to samo, bez konieczności sprawdzania, na jaki stół wskazali. 13 w tej samej kolumnie może potencjalnie być kluczem podstawowym w innej tabeli. Jestem bardzo niewygodny z tym stylem projektowania.
Lawtonfogle
@AaronBertrand Lub alternatywnie użyj prostych identyfikatorów całkowitych i dodaj kod na początku, gdy są one skierowane do klienta. na przykład. I1337, C1337 wyraźnie faktura lub klient
JamesRyan
7

Pomysł ten ma swoje zalety w bardzo złożonej bazie danych, w której ludzie mogą przypadkowo dołączyć do tabeli przy użyciu niewłaściwej kolumny i uzyskać nieprawidłowe wiersze tylko dlatego, że identyfikatory INT są takie same.

Zdecydowaliśmy się na sekwencyjne GUID jako nasze klucze główne, aby uniknąć niektórych pułapek fragmentacji indeksu GUID. Niestety są dość duże.

Serwer SQL może generować sekwencyjne identyfikatory GUID za pomocą domyślnego wywołania funkcji newSequentialID (), więc nie ma tabeli wydawanych kluczy do utrzymania i nie ma blokowania wąskiego gardła.

Dzięki temu otrzymaliśmy unikalne identyfikatory we wszystkich bazach danych, w całym naszym przedsiębiorstwie, ponieważ są naprawdę wyjątkowe.

Cena oczywiście jest przestrzenią i jest problematyczna, gdy próbujesz przenieść dane do hurtowni danych / kostki, w której prędkość / rozmiar zależy od użycia mniejszych kluczy całkowitych.

Jestem przekonany, że uniknęliśmy wielu błędów w naszej aplikacji w wyniku ich używania.

RayG
źródło
4

Nie mogę sobie wyobrazić, co może być przyczyną pojedynczej sekwencji we wszystkich tabelach. Wszystko, co robi, to tworzenie wąskiego gardła podczas generowania nowych wartości.

Bez względu na to, jak niewielki jest narzut związany z generowaniem sekwencyjnych wartości kluczy, generator jest pojedynczym zasobem, do którego dostęp musi być zsynchronizowany. Im więcej otrzyma żądań, tym większe są szanse, że niektórzy żądający będą musieli czekać na swoją kolej przy kranu. Oczywiste jest, że do generatora pojedynczej sekwencji współużytkowanego przez wszystkie tabele będzie częściej uzyskiwać dostęp więcej klientów, co spowoduje większą rywalizację niż jakikolwiek z wielu generatorów. Spór może stać się bardziej wyraźny, jeśli reguły biznesowe nakładają ograniczenia na generowane wartości, takie jak brak luk lub ścisłe porządkowanie, lub w klastrowej bazie danych.

Nawet przy najbardziej wydajnym generatorem sekwencji nie będzie obciążenie pracą, która powoduje untolerable rywalizacji.

mustaccio
źródło
2
Możesz dodać szczegóły dotyczące tego, jak powstaje wąskie gardło i dlaczego jest to zły pomysł.
Max Vernon
2

celem PrimaryKey w tabelach bazy danych jest przede wszystkim wymuszenie wyjątkowości danych, które powinny być unikalne, ponieważ nie można uwzględnić wszystkich przepływów pracy i zapewnić, że nie spowoduje to powielania danych. Drugi powód jest taki, że PK często jest również głównym kandydatem do indeksowania klastrowego w tabeli, więc również zwiększa pobieranie danych, gdy / gdzie kolumny te są właściwie używane w wybranym zapytaniu.

użycie numeru sekwencyjnego jako klucza podstawowego jest takie samo, ponieważ każda tabela ma kolumnę Tożsamość i tylko ta kolumna jest używana w PrimaryKey. posiadanie jednego numeru sekwencyjnego w DB musi mieć określone zastosowanie, ale z punktu widzenia PrimaryKey nie rozumiem powodu. na przykład w jednym z projektów Datawarehouse, nad którymi pracowałem, mamy Kolumnę o nazwie LoadBatchID i od ETL do raportowania 50% całej tabeli ma tę kolumnę, ale w niektórych miejscach ma inne znaczenie. użyliśmy unikalnego proc jako generatora liczb, aby upewnić się, że nie znajdziemy konfliktów, a także pomóc nam w odnalezieniu oryginalnego pliku, z którego pochodzą dane i co dzieje się na poszczególnych etapach ETL.

Anup Shah
źródło
2

Przypuszczam, że jednym z powodów tego byłoby, gdyby wszystkie byty odziedziczyły po jakimś bycie nadrzędnym. Powiedz na przykład, że chcesz móc komentować dowolny typ encji:

create table god_entity (
  id bigserial primary key
);

create table some_table (
  id bigint primary key references god_entity(id),
  ...
);

create table some_other_table (
  id bigint primary key references god_entity(id),
  ...
);

create table comment (
  id bigint primary key references god_entity(id),
  ...
);

create table entity_comment (
  entity_id bigint not null references god_entity(id),
  comment_id bigint not null references god_entity(id),

  primary key (entity_id, comment_id)
);

Zwykle nie jest to robione. .

Nie wiem o charakterystykach wydajności.

Neil McGuigan
źródło