Ich habe Probleme, genau herauszufinden, wie gute Grenzen gesetzt werden können, 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 die Datenbank in so viele Teile zerlegt zu sein, dass sie zwar effizient, aber nicht mehr verwaltbar ist. Hier ist ein Beispiel, mit dem ich zusammenarbeite:
Angenommen, ich habe eine Tabelle mit dem Namen Mitarbeiter:
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 Tabelle Positionen in die Tabelle Mitarbeiter in der Spalte Position stecken.
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 Gender-Tabelle erstellen und eine 1 für männlich und eine 2 für weiblich in einer separaten Nachschlagetabelle haben. 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, die besagt, dass eine ID von 1 John entspricht. Wenn Sie dieses Kaninchenloch jedoch zu weit hinuntergehen, wird Ihre Mitarbeitertabelle 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 ist oder nicht, ist dies für eine normale Person, die versucht, es zu warten, sicherlich nicht lesbar und erschwert es einem Anwendungsentwickler, auf ihn zuzugreifen. Meine eigentliche Frage ist also, wie weit ist zu weit? Gibt es irgendwo "Best Practices" für diese Art von Dingen oder eine Reihe guter Richtlinien? Ich kann online keine Informationen finden, die wirklich gute, brauchbare 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 meinen Kopf gehen können. Jede Hilfe wäre dankbar!
Aber wie weit kann ich die Informationen weiterhin in kleinere Nachschlagetabellen aufteilen, bevor sie nicht mehr verwaltet werden können? Ich könnte eine Gender-Tabelle erstellen und eine 1 für männlich und eine 2 für weiblich in einer separaten Nachschlagetabelle haben.
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 Positionen wie diese 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. Und die Tabelle der Mitarbeiter erfordert keine zusätzlichen Verknüpfungen, um nützliche, für Menschen lesbare Daten daraus zu erhalten.
Die Verwendung einer "Nachschlagetabelle" läuft auf Folgendes hinaus: Benötigt Ihre Anwendung die Kontrolle über Eingabewerte, die eine Fremdschlüsselreferenz bereitstellt? Wenn ja, 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 zur Laufzeit Zeilen zu dieser Tabelle hinzufügen können. (Und Sie müssen wahrscheinlich einige Verwaltungsprozesse einbeziehen, um neue Daten zu überprüfen.) Das Geschlecht, das tatsächlich einen ISO-Standard hat, kann zur Entwurfszeit vollständig ausgefüllt werden. Straßennamen für internationale Online-Produktbestellungen müssen wahrscheinlich zur Laufzeit hinzugefügt werden.
In Ihrer Employees-Tabelle würde ich nur nach "Position" suchen, da es sich um einen begrenzten Datensatz handelt, der erweitert werden kann.
M
oder F
), auf 2 Werte begrenzt und kann mit einer CHECK-Einschränkung erzwungen werden. Sie werden keine neuen Geschlechter hinzufügen (politische Korrektheit ignorieren).Wenn Sie eine neue Position hinzufügen möchten, fügen Sie der Nachschlagetabelle einfach eine Zeile hinzu. Dadurch werden auch Datenänderungsanomalien entfernt, was ein Punkt der Normalisierung ist
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 durch eine CHECK-Einschränkung wie Geschlecht eingeschränkt werden, es handelt sich jedoch um einen begrenzten, aber erweiterbaren Datensatz wie Position. Ich gebe dieses Beispiel, weil ich den natürlichen Schlüssel verwenden würde, selbst wenn er in einer Million Zeilen von Mitarbeiterdaten angezeigt wird, obwohl er eher char (3) als tinyint ist
Zusammenfassend verwenden Sie also Nachschlagetabellen
Die Antwort lautet "es kommt darauf an". Nicht sehr befriedigend, aber es gibt viele Einflüsse, die das Design drücken und ziehen. Wenn App-Programmierer die Datenbank entwerfen, funktioniert eine von Ihnen beschriebene Struktur für sie, da der ORM die Komplexität verbirgt. Sie werden sich beim Schreiben von Berichten die Haare ausreißen und müssen an zehn Tischen teilnehmen, um eine Adresse zu erhalten.
Design für die Verwendung, den beabsichtigten Gebrauch 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 Anweisungen in Bezug auf die Funktionalität, die sich erheblich von denen eines High-Tech-Start-ups unterscheiden.
Ein Lieblingszitat wiederverwenden
Irgendwo drin ist der Sweet Spot. Ich habe die Erfahrung gemacht, dass es nicht so schwerwiegend ist, eine Schlüssel-ID in mehr als einer Tabelle zu haben, wie manche denken, wenn Sie niemals Primärschlüssel ändern.
Nehmen Sie dieses abgekürzte Beispiel für stark normalisierte 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 erstellen eine verknüpfte Liste einzelner Eigenschaften und übergeordneter untergeordneter Eigenschaften und werden hier verwendet
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 zur Auswahl bekommen
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 Eigenschaftstypen von 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 wenig 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, wann Sie zu viele Tabellen haben oder nicht genug, versuchen Sie, die Datenbank mit Fragen abzufragen, die die Anwendung, ein Bericht und eine Analyse von Jahr zu Jahr verwenden.