Richtige Verwendung von Nachschlagetabellen

25

Ich habe Probleme, genau herauszufinden, wie man gute Grenzen setzt, wann und wo Nachschlagetabellen in einer Datenbank verwendet werden sollen. Die meisten Quellen, die ich mir angesehen habe, sagen, dass ich nie zu viele haben kann, aber irgendwann scheint es, als würde die Datenbank in so viele Teile zerlegt, dass sie zwar effizient ist, aber nicht mehr verwaltet werden kann. Hier ist ein Beispiel, mit dem ich zusammenarbeite:

Nehmen wir an, ich habe eine Tabelle namens Employees:

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

Stellen Sie sich für einen Moment vor, dass die Daten komplexer sind und Hunderte von Zeilen enthalten. Das offensichtlichste, was ich sehe, das in eine Nachschlagetabelle verschoben werden könnte, wäre Position. Ich könnte eine Tabelle mit dem Namen Positionen erstellen und die Fremdschlüssel aus der Positionstabelle in die Employees-Tabelle in der Position-Spalte einfügen.

ID  Position
1   Manager
2   Sales

Aber wie weit kann ich die Informationen weiterhin in kleinere Nachschlagetabellen aufteilen, bevor sie nicht mehr verwaltet werden können? Ich könnte eine Geschlechtstabelle erstellen und in einer separaten Nachschlagetabelle eine 1 für "Männlich" und eine 2 für "Weiblich" angeben. Ich könnte sogar LNames und FNames in Tabellen einfügen. Alle "John" -Einträge werden durch einen Fremdschlüssel von 1 ersetzt, der auf die FName-Tabelle verweist, in der angegeben ist, dass eine ID von 1 John entspricht. Wenn Sie dieses Kaninchenloch jedoch zu weit hinuntergehen, wird Ihre Employees-Tabelle auf ein Durcheinander von Fremdschlüsseln reduziert:

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

Während dies für einen Server möglicherweise effizienter oder nicht effizienter ist, ist es für eine normale Person, die versucht, es zu warten, sicherlich nicht lesbar, und es wird für einen Anwendungsentwickler, der versucht, darauf zuzugreifen, schwieriger. Meine eigentliche Frage ist also, wie weit ist es zu weit? Gibt es "Best Practices" für diese Art von Dingen oder irgendwo eine gute Reihe von Richtlinien? Ich kann online keine Informationen finden, die wirklich nützliche Richtlinien für dieses spezielle Problem enthalten. Datenbankdesign ist für mich ein alter Hut, aber GUTES Datenbankdesign ist sehr neu, so dass übermäßig technische Antworten über meinem Kopf sein können. Jede Hilfe wäre dankbar!

Brad Turner
quelle
5
Das Verwenden von "Nachschlagetabellen" ist eine Sache. Das Ersetzen von Text durch ID-Nummern ist eine völlig andere Sache.
Mike Sherrill 'Cat Recall'
1
Das Geschlecht ist möglicherweise nicht immer auf 2 Werte festgelegt! Da es nun geschlechtsspezifische Übergänge gibt, sind für eine Bewerbung möglicherweise keine zusätzlichen Kategorien wie "Geborener Mann, jetzt Frau" oder "Geborener Mann, jetzt Frau" erforderlich.
@ Mike, guter Kommentar!
Walter Mitty
In meinem Laden konnten die Denker aufhören, nachdem nur vier Entscheidungen, männlich, weiblich, transgender, nicht offengelegt wurden.
Kevin

Antworten:

22

Aber wie weit kann ich die Informationen weiterhin in kleinere Nachschlagetabellen aufteilen, bevor sie nicht mehr verwaltet werden können? Ich könnte eine Geschlechtstabelle erstellen und in einer separaten Nachschlagetabelle eine 1 für "Männlich" und eine 2 für "Weiblich" angeben.

Sie mischen zwei verschiedene Themen. Ein Problem ist die Verwendung einer "Nachschlagetabelle"; Das andere ist die Verwendung von Ersatzschlüsseln (ID-Nummern).

Beginnen Sie mit dieser Tabelle.

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

Sie können eine Nachschlagetabelle für solche Positionen erstellen.

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);

Ihre ursprüngliche Tabelle sieht genauso aus wie vor dem Erstellen der Nachschlagetabelle. Für die Tabelle der Mitarbeiter sind keine zusätzlichen Verknüpfungen erforderlich , um nützliche, für den Menschen lesbare Daten zu erhalten.

Die Verwendung einer "Nachschlagetabelle" führt zu folgendem Ergebnis: Benötigt Ihre Anwendung die Kontrolle über die Eingabewerte, die eine Fremdschlüsselreferenz bereitstellt? In diesem Fall können Sie immer eine Nachschlagetabelle verwenden. (Unabhängig davon, ob ein Ersatzschlüssel verwendet wird.)

In einigen Fällen können Sie diese Tabelle zur Entwurfszeit vollständig füllen. In anderen Fällen müssen Benutzer in der Lage sein, dieser Tabelle zur Laufzeit Zeilen hinzuzufügen. (Und Sie müssen wahrscheinlich einige administrative Prozesse einbeziehen, um neue Daten zu überprüfen.) Das Geschlecht, für das tatsächlich ein ISO-Standard gilt , kann zur Entwurfszeit vollständig ausgefüllt werden. Straßennamen für internationale Online-Produktbestellungen müssen wahrscheinlich zur Laufzeit hinzugefügt werden.

Mike Sherrill 'Cat Recall'
quelle
2
Ich wusste nicht, dass du das alles kannst! Die Art und Weise, wie Ihre Methode funktioniert, ist ziemlich schön. Vielen Dank!
Brad Turner
4
Ich bin DBA Stack Exchange beigetreten, um diese Antwort zu bewerten. Das ist wunderschön und ist mir nie in den Sinn gekommen. Vielen Dank!
CindyH
Ich schätze die Methode zum Auffüllen der Nachschlagetabelle. Mein Grund für das Lesen dieser Frage war, zu sehen, ob es einen Vorteil gibt, den ich nicht für einen Ersatzschlüssel auf meinen Nachschlagetabellen sehen kann. Sie haben für mich bestätigt, dass ein einzelnes Textfeld so gut und nützlich ist, wie es erscheint. Vielen Dank.
Sinthia V
8

In Ihrer Employees-Tabelle würde ich nur nach "Position" suchen, da dies eine begrenzte Menge von Daten ist, die erweitert werden können.

  • Das Geschlecht ist selbstbeschreibend (etwa Moder F), auf 2 Werte beschränkt und kann mit einer CHECK-Einschränkung erzwungen werden. Sie werden keine neuen Geschlechter hinzufügen (politische Korrektheitsbolde ignorieren)
  • Der Vorname "John" ist nicht Teil einer begrenzten, eingeschränkten Datenmenge: Die potenzielle Datenmenge ist so umfangreich, dass sie praktisch unbegrenzt ist, und sollte daher nicht nachgeschlagen werden

Wenn Sie eine neue Position hinzufügen möchten, fügen Sie der Nachschlagetabelle einfach eine Zeile hinzu. Dies beseitigt auch Datenänderungsanomalien, die ein Punkt der Normalisierung sind

Sobald Sie eine Million Mitarbeiter haben, ist es effizienter, tinyint PositionID als varchar zu speichern.

Fügen wir eine neue Spalte "Gehaltswährung" hinzu. Ich würde hier eine Nachschlagetabelle mit einem Schlüssel von CHF, GBP, EUR, USD usw. verwenden: Ich würde keinen Ersatzschlüssel verwenden. Dies könnte mit einer CHECK-Einschränkung wie dem Geschlecht eingeschränkt werden, es handelt sich jedoch um einen begrenzten, jedoch erweiterbaren Datensatz wie Position. Ich gebe dieses Beispiel an, weil ich den natürlichen Schlüssel verwenden würde, auch wenn er in einer Million Zeilen mit Mitarbeiterdaten vorkommt, obwohl er char (3) und nicht tinyint ist

Zusammenfassend verwenden Sie also Nachschlagetabellen

  1. wo Sie eine endliche, aber erweiterbare Menge Daten in einer Spalte haben
  2. Wo ist, ist nicht selbstbeschreibend
  3. um Datenänderungsanomalien zu vermeiden
gbn
quelle
1
Ein möglicher Grund, das Geschlecht in eine Nachschlagetabelle aufzunehmen, ist die Lokalisierung.
a_horse_with_no_name
1
"Geschlecht ... (sagen Sie M oder F), begrenzt auf 2 Werte ... politische Korrektheit ignorieren" - Ironischerweise ist es genau dieselbe politische Korrektheit, die Sie zu verabscheuen scheinen, die Menschen dazu bringt, falsch "Geschlecht" (' "Männlich", "Weiblich", wenn sie "Geschlecht" ("Männlich", "Weiblich") bedeuten. Wenn der Kontext grammatikalisches Geschlecht ist, gibt es normalerweise mehr als zwei Werte. Wenn der Kontext das Geschlecht eines Neugeborenen aufzeichnet, gibt es mindestens vier Werte ("wurde nicht offiziell bewertet" und "offizielle Bewertung war nicht schlüssig"). ps Ich will nicht hart klingen, ich habe die Ironie genossen :)
onedaywhen
4
@onedaywhen: Der richtige Wert für eine Spalte mit dem Namen "Geschlecht" lautet "Ja, bitte". Es sei denn, Sie sind Brite
gbn
Der Begriff "Anomolien" wird hier missbraucht, da der Begriff im Zusammenhang mit der Normalisierung eine andere besondere Bedeutung hat und die Verknüpfung unangemessen ist.
Philipxy
5

Die Antwort ist ein "es kommt darauf an". Nicht sehr befriedigend, aber es gibt viele Einflüsse, die das Design drücken und ziehen. Wenn Sie App-Programmierer haben, die die Datenbank entwerfen, funktioniert eine Struktur, wie Sie sie beschreiben, für sie, da der ORM die Komplexität verbirgt. Sie werden sich die Haare ausreißen, wenn Sie Berichte schreiben und zehn Tische zusammenstellen müssen, um eine Adresse zu erhalten.

Design für den Gebrauch, die beabsichtigte Verwendung und die wahrscheinliche zukünftige Verwendung. Hier kommt Ihr Wissen über den Geschäftsprozess ins Spiel. Wenn Sie eine Datenbank für ein Veterinärunternehmen entwerfen, gibt es vernünftige Annahmen über Größe, Verwendung und Funktionsweise, die sich erheblich von denen eines High-Tech-Start-ups unterscheiden.

Ein Lieblingszitat wiederverwenden

"Ein weiser Mann sagte mir einmal" normalisieren, bis es weh tut, denormalisieren, bis es funktioniert ".

Irgendwo drin ist der Sweet Spot. Ich habe die Erfahrung gemacht, dass das Vorhandensein einer Schlüssel-ID in mehr als einer Tabelle kein so schwerwiegendes Verbrechen ist, wie manche meinen, wenn Sie niemals den Primärschlüssel ändern.

Nehmen Sie dieses abgekürzte Beispiel stark normalisierter Tabellen aus einem realen System

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);

Diese Tabellen enthalten eine verknüpfte Liste mit einzelnen Eigenschaften und übergeordneten untergeordneten Eigenschaften, die hier verwendet werden

  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);

Das sieht gut aus: Holen Sie sich alle Fälle mit einer property_id in einer Auswahl

Lassen Sie uns eine Liste zusammenstellen

 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

Versuchen Sie nun, alle Eigenschaften eines Falls auszuwählen, wenn er die property_types 3 und 4 und 5 hat oder nicht ...

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  

Das tut einfach weh ... auch wenn Sie eleganter damit umgehen. Fügen Sie jedoch ein bisschen De-Normalisierung hinzu, indem Sie Eigenschaften aufteilen, für die ein Fall nur eine property_id hat, und dies könnte viel besser sein.

Um herauszufinden, ob zu viele Tabellen vorhanden sind oder nicht, sollten Sie die Datenbank mit Fragen abfragen, die von der Anwendung, einem Bericht und einer Analyse von Jahr zu Jahr verwendet werden.

Kevin
quelle
5
ID-Nummern haben nichts mit Normalisierung zu tun. Nur weil jeder Tisch eine ID-Nummer hat, heißt das nicht, dass er in 5NF oder sogar in 3NF ist. Es bedeutet nur, dass Sie viele Verknüpfungen ausführen müssen, um verwendbare Daten aus dieser Tabelle zu erhalten.
Mike Sherrill 'Cat Recall'