Właściwe korzystanie z tabel odnośników

25

Mam problem z ustaleniem, jak dokładnie ustalić granice, kiedy i gdzie należy używać tabel odnośników w bazie danych. Większość źródeł, na które patrzyłem, mówi, że nigdy nie mogę mieć ich zbyt wiele, ale w pewnym momencie wygląda na to, że baza danych zostałaby podzielona na tak wiele części, że chociaż może być wydajna, nie jest już zarządzalna. Oto ogólny przykład tego, nad czym pracuję:

Powiedzmy, że mam tabelę o nazwie Pracownicy:

ID  LName   FName   Gender  Position
1   Doe     John    Male    Manager
2   Doe     Jane    Female  Sales
3   Smith   John    Male    Sales

Udawaj przez chwilę, że dane są bardziej złożone i zawierają setki wierszy. Najbardziej oczywistą rzeczą, którą widzę, którą można przenieść do tabeli odnośników, jest Pozycja. Mógłbym utworzyć tabelę o nazwie Pozycje i przykleić klucze obce z tabeli Pozycje do tabeli Pracownicy w kolumnie Pozycja.

ID  Position
1   Manager
2   Sales

Ale jak daleko mogę nadal dzielić informacje na mniejsze tabele wyszukiwania, zanim stanie się to niemożliwe do zarządzania? Mógłbym utworzyć tabelę Płeć i mieć 1 odpowiadającą Mężczyzna i 2 odpowiadającą Kobiecie w osobnej tabeli odnośników. Mógłbym nawet umieścić LName i FNames w tabelach. Wszystkie wpisy „John” są zastępowane kluczem obcym 1, który wskazuje na tabelę FName, która mówi, że identyfikator 1 odpowiada Johnowi. Jeśli jednak zejdziesz w dół do tej króliczej nory zbyt daleko, stół Twoich pracowników zostanie zredukowany do bałaganu obcych kluczy:

ID  LName   FName   Gender  Position
1   1       1       1       1
2   1       2       2       2
3   2       1       1       2

Chociaż może to być lub nie być bardziej wydajne dla serwera do przetworzenia, jest to z pewnością nieczytelne dla normalnej osoby, która może próbować go utrzymać i utrudnia programistom aplikacji próbującym uzyskać do niego dostęp. Więc moje prawdziwe pytanie brzmi: jak daleko jest za daleko? Czy są gdzieś „najlepsze praktyki” dla tego rodzaju rzeczy lub dobry zestaw wytycznych? Nie mogę znaleźć w Internecie żadnych informacji, które naprawdę zawiodłyby dobry, użyteczny zestaw wskazówek dotyczących tego konkretnego problemu, który mam. Projektowanie bazy danych to dla mnie stary styl, ale DOBRY projekt bazy danych jest bardzo nowy, więc zbyt techniczne odpowiedzi mogą być nad moją głową. Każda pomoc będzie mile widziana!

Brad Turner
źródło
5
Korzystanie z tabel „odnośników” to jedno. Zamiana tekstu na numery identyfikacyjne to zupełnie inna sprawa.
Mike Sherrill „Cat Recall”
1
Płeć nie zawsze może być ustalona na 2 wartości! Teraz, gdy mamy zmiany płci, co oznacza, że ​​aplikacja może nie potrzebować dodatkowych kategorii, takich jak „urodzony mężczyzna teraz kobieta” lub „urodzona kobieta teraz mężczyzna”.
@Mike, dobry komentarz!
Walter Mitty
W moim sklepie myśliciele byli w stanie zatrzymać się dopiero po czterech wyborach: mężczyzna, kobieta, osoba transpłciowa nie ujawniali się.
kevinsky

Odpowiedzi:

22

Ale jak daleko mogę nadal dzielić informacje na mniejsze tabele wyszukiwania, zanim stanie się to niemożliwe do zarządzania? Mógłbym utworzyć tabelę Płeć i mieć 1 odpowiadającą Mężczyzna i 2 odpowiadającą Kobiecie w osobnej tabeli odnośników.

Mieszasz dwa różne problemy. Jednym z problemów jest użycie tabeli „wyszukiwania”; drugim jest użycie kluczy zastępczych (numerów identyfikacyjnych).

Zacznij od tej tabeli.

ID  LName   FName   Gender  Position
1   Doe     John    Male    Manager
2   Doe     Jane    Female  Sales
3   Smith   John    Male    Sales

Możesz utworzyć tabelę „lookup” dla takich pozycji.

create table positions (
  pos_name varchar(10) primary key
);

insert into positions
select distinct position 
from employees;

alter table employees
add constraint emp_fk1
foreign key (position) 
  references positions (pos_name);

Oryginalna tabela wygląda dokładnie tak, jak przed utworzeniem tabeli „odnośnika”. A tabela pracowników nie wymaga żadnych dodatkowych połączeń, aby uzyskać z niej użyteczne, czytelne dla człowieka dane.

Korzystanie z tabeli „wyszukiwania” sprowadza się do tego: czy Twoja aplikacja potrzebuje kontroli nad wartościami wejściowymi zapewnianymi przez odwołanie do klucza obcego? Jeśli tak, to zawsze możesz użyć tabeli „wyszukiwania”. (Niezależnie od tego, czy używa klucza zastępczego.)

W niektórych przypadkach będziesz w stanie całkowicie wypełnić tę tabelę w czasie projektowania. W innych przypadkach użytkownicy muszą mieć możliwość dodawania wierszy do tej tabeli w czasie wykonywania. (I prawdopodobnie będziesz musiał uwzględnić pewne procesy administracyjne, aby przejrzeć nowe dane.) Płeć, która faktycznie ma standard ISO , może być całkowicie wypełniona w czasie projektowania. Nazwy ulic w międzynarodowych zamówieniach produktów online prawdopodobnie należy dodać w czasie wykonywania.

Mike Sherrill „Cat Recall”
źródło
2
Nie wiedziałem, że możesz to wszystko zrobić! Sposób, w jaki działa Twoja metoda, jest dość piękny. Dziękuję Ci!
Brad Turner
4
Dołączyłem do DBA Stack Exchange, aby móc głosować na tę odpowiedź. To jest piękne i nigdy nie przyszło mi do głowy. Dzięki!
CindyH
Doceniam metodę zapełniania tabeli odnośników. Moim powodem, dla którego przeczytałem to pytanie, było sprawdzenie, czy przyniosłabym korzyść, której nie dostrzegałbym w zastępczym kluczu moich tabel odnośników. Potwierdziłeś, że jedno pole tekstowe jest tak dobre i przydatne, jak się wydaje. Dziękuję Ci.
Sinthia V
8

W twojej tabeli pracowników będę szukał tylko „pozycji”, ponieważ jest to ograniczony zestaw danych, który można rozwinąć.

  • Płeć samoopisuje się (powiedz Mlub F), jest ograniczone do 2 wartości i można je wymusić za pomocą ograniczenia CHECK. Nie dodasz nowych płci (ignorując bzdury poprawności politycznej)
  • Imię „John” nie jest częścią ograniczonego, ograniczonego zestawu danych: potencjalny zestaw danych jest ogromny do tego stopnia, że ​​jest praktycznie nieograniczony, więc nie powinien to być przegląd

Jeśli chcesz dodać nową pozycję, po prostu dodaj wiersz do tabeli odnośników. Usuwa to również anomalie modyfikacji danych, co stanowi jeden punkt normalizacji

Ponadto, gdy masz milion pracowników, bardziej efektywne jest przechowywanie tinyint PositionID niż varchar.

Dodajmy nową kolumnę „waluta pensji”. Użyłbym tu tabeli odnośników z kluczem CHF, GBP, EUR, USD itp .: Nie użyłbym klucza zastępczego. Można to ograniczyć za pomocą ograniczenia CHECK, takiego jak Płeć, ale jest to ograniczony, ale rozszerzalny zestaw danych, takich jak Pozycja. Podaję ten przykład, ponieważ użyłbym klucza naturalnego, nawet jeśli pojawia się on w milionie wierszy danych pracowników, mimo że jest char (3), a nie malutki

Podsumowując, korzystasz z tabel odnośników

  1. gdzie masz skończone, ale rozwijalne dane zestawu w kolumnie
  2. gdzie nie jest samoopisujące
  3. aby uniknąć anomalii modyfikacji danych
gbn
źródło
1
Jednym z możliwych powodów umieszczenia płci w tabeli odnośników jest lokalizacja.
a_horse_w_no_name
1
„Płeć ... (powiedzmy M lub F), ograniczone do 2 wartości… ignorowanie bzdur poprawności politycznej” - Jak na ironię, to ta sama polityczna poprawność, której zdajesz się brzydzić, powoduje, że ludzie błędnie „płci” („ „Męski”, „żeński”), gdy mają na myśli „seks” („mężczyzna”, „kobieta”). Jeśli kontekstem jest płeć gramatyczna, wówczas zwykle występują więcej niż dwie wartości. Jeśli w kontekście rejestrowana jest płeć noworodka, istnieją co najmniej cztery wartości („nie została oficjalnie oceniona”, a „oficjalna ocena nie była jednoznaczna”). ps Nie chcę zabrzmieć ostro, podobała mi się ironia :)
dniu
4
@onedaywhen: poprawna wartość dla kolumny o nazwie „Seks” to „Tak, proszę”. Jeśli nie jesteś brytyjski
gbn
Termin „anomolie” jest tutaj niewłaściwie używany, ponieważ termin ten ma inne szczególne znaczenie związane z normalizacją, a link jest nieodpowiedni.
philipxy
5

Odpowiedź brzmi „to zależy”. Niezbyt satysfakcjonujące, ale istnieje wiele czynników popychających i pociągających za projekt. Jeśli masz programistów aplikacji projektujących bazę danych, struktura taka jak opisana działa dla nich, ponieważ ORM ukrywa złożoność. Będziesz wyciągać włosy, gdy piszesz raporty i musisz dołączyć do dziesięciu stolików, aby uzyskać adres.

Projekt zastosowania, zamierzone zastosowanie i prawdopodobne zastosowanie w przyszłości. W tym miejscu pojawia się Twoja wiedza na temat procesu biznesowego. Jeśli projektujesz bazę danych dla firmy weterynaryjnej, istnieją uzasadnione założenia dotyczące wielkości, wykorzystania i kierunków działania, które będą zupełnie inne niż start-up w zaawansowanych technologiach.

Aby ponownie użyć ulubionego cytatu

„Mądry człowiek powiedział mi kiedyś:„ normalizuj, aż boli, denormalizuj, aż działa ”.

Gdzieś tam jest słodkie miejsce. Z mojego doświadczenia wynika, że ​​posiadanie identyfikatora klucza w więcej niż jednym stole nie jest tak poważnym przestępstwem, jak niektórzy sądzą, jeśli nigdy nie zmienisz kluczy podstawowych.

Weź ten skrócony przykład wysoce znormalizowanych tabel z prawdziwego systemu

CREATE TABLE PROPERTY
(ID                          NUMBER(9)           NOT NULL);

CREATE TABLE PROPERTY_TYPE
(ID                          NUMBER(9)           NOT NULL);

CREATE TABLE PROPERTY_LOCALE 
PROPERTY_ID                  NUMBER(9)           NOT NULL,
(LOCALE_ID                   NUMBER(9)           NOT NULL,  --language 
VALUE                        VARCHAR2(200)       NOT NULL);

CREATE TABLE PROPERTY_DEPENDENCY
(PROPERTY_ID                 NUMBER(9)           NOT NULL,
 PARENT_PROPERTY_ID          NUMBER(9)                   ,
 PROPERTY_TYPE_ID            NUMBER(9)           NOT NULL);

Te tabele tworzą połączoną listę pojedynczych właściwości i nadrzędnych właściwości potomnych i są one używane tutaj

  CREATE TABLE CASE_PROPERTY
  (ID                        NUMBER(9)           NOT NULL,
  PARENT_ID                  NUMBER(9),
  CASE_ID                    NUMBER(9)           NOT NULL,
  PROPERTY_ID                NUMBER(9),
  PROPERTY_TYPE_ID           NUMBER(9)           NOT NULL);

Wygląda to dobrze: pobierz wszystkie przypadki z właściwością id_właściwości w jednym zaznaczeniu

Zdobądźmy listę do wyboru

 Select pl.value, pd.property_id
 from property_locale pl, property_dependency pd
 where pl.property_id = pd.property_id
 and pd.property_type_id = 2;  --example number

Teraz spróbuj wybrać wszystkie właściwości sprawy, jeśli ma ona typy właściwości 3 i 4 oraz 5, lub nie ...

SELECT   cp2.case_id,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 2
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE1,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 34
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE2,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 4
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE3
  FROM   case_property cp2
 WHERE   cp2.case_id = 10293  

To po prostu boli ... nawet jeśli używasz bardziej eleganckich sposobów radzenia sobie z tym. Dodaj jednak trochę dezormalizacji, wyodrębniając właściwości, dla których sprawa będzie miała tylko jeden identyfikator_właściwości, a to może być znacznie lepsze.

Aby dowiedzieć się, kiedy masz zbyt wiele tabel lub za mało, spróbuj przeszukać bazę danych pytaniami, z których skorzysta aplikacja, raport i analiza z roku na rok.

Kevinsky
źródło
5
Numery identyfikacyjne nie mają nic wspólnego z normalizacją. To, że każda tabela ma numer identyfikacyjny, nie oznacza, że ​​jest w 5NF, a nawet w 3NF. Oznacza to po prostu, że musisz wykonać wiele połączeń, aby uzyskać przydatne dane z tej tabeli.
Mike Sherrill „Cat Recall”