4 Stimmen

Ist es gut oder übertrieben, wenn jede Spalte in einer Tabelle ein Fremdschlüssel ist?

Ich baue eine Datenbank mit möglichen Fahrzeugen auf, wobei jeder Eintrag eine Marke, ein Modell, ein Jahr und einen Motor enthält.

Ich habe das in eine Tabelle der Marken (Ford, Chevrolet, BMW usw.) und Modelle (Impala, Camaro, F-150 usw.) und Jahre (1920, ... 2012) und Motoren (327, 350 usw.) aufgeteilt.

Da ich nun für jede Marke, jedes Modell, jedes Jahr und jeden Motor eine eigene Tabelle habe, die jeweils einen eindeutigen Primärschlüssel haben kann, besteht jede Zeile in der Haupttabelle "MarkenModelleJahre" nur aus vier Fremdschlüsseln.

Ist dies übertrieben, oder wirklich effizienter gespeichert als nur eine große Tabelle, wo ich eindeutige Indizes erstellt? Meine Besorgnis mit der "eine große Tabelle" Ansatz ist, dass die Jahre, wie 1970, würde viele Male (1970 Chevrolet Impala, 1969 Chevrolet Camaro, etc.) wiederholt werden, wie würde Modell und sogar Motor haben.

Vielen Dank für jede Hilfe!

enter image description here

Nachbereitung:

Für diejenigen, die mitlesen, habe ich das Feedback in den Antworten berücksichtigt und bin zu diesem Schema gekommen. Das Bild zeigt die FKs nicht im Detail, aber sie sind tatsächlich das, was die Antwort vorgeschlagen hat:

enter image description here

6voto

ypercubeᵀᴹ Punkte 109378

Es ist überhaupt kein Problem, eine Tabelle mit 2, 3, 4 oder mehr Fremdschlüsseln zu haben, und der Primärschlüssel ist die Kombination dieser FKs, wenn das zu Ihrem Modell passt.

Das einzige Problem, das ich bei diesem Entwurf sehe, ist, dass er einen "BMW Escort" oder einen "Ford Z4" zulässt. Vielleicht können Sie das Design zu ändern:

Makes
-----
Make PK

Models
------
Make  PK, FK to Makes
Model PK

MakesModelsAndYears
-------------------
Year       PK, FK1 to Years
Make       PK, FK2 to Model
Model      PK, FK2
EngineSize PK, FK3 to Engines

5voto

Chevrolet stellt keinen Mustang her. Ford hat 1960 keinen Mustang hergestellt. Ihre Struktur wird eine Menge Unsinn zulassen.

Das Problem besteht nicht darin, dass jede Spalte ein Fremdschlüssel ist; daran ist nicht unbedingt etwas auszusetzen. Das Problem ist, dass die Fremdschlüssel falsch sind.

Ich habe das in eine Tabelle der Marken (Ford, Chevrolet, BMW usw.) und Modelle (Impala, Camaro, F-150 usw.) und Jahre (1920, ... 2012) und Motoren (327, 350 usw.) aufgeteilt.

Und genau deshalb sind sie falsch. Wenn Sie eine Beziehung normalisieren, müssen Sie Start mit der Beziehung, ermitteln die Schlüsselkandidaten und arbeiten die funktionalen Abhängigkeiten aus. Einfach nur einspaltige "Nachschlagetabellen" für jede Spalte zu erstellen, ist keine Normalisierung und schränkt Ihre Daten nicht in der erforderlichen Weise ein. (Und in diesem speziellen Fall sind die Beschränkungen das fehlende Element, nicht die Normalisierung auf 5NF).

Make       Model   Yr    Engine
--
Ford       F-150   2012  3.7L V6
Ford       F-150   2012  3.5L V6 EcoBoost
Ford       F-150   2012  5.0L V8
Ford       F-150   2012  6.2L V8
Ford       F-150   2011  3.7L V6
Ford       F-150   2011  3.5L V6 EcoBoost
Ford       F-150   2011  5.0L V8
Ford       F-150   2011  6.2L V8
Chevrolet  Camaro  2012  3.6L V6
Chevrolet  Camaro  2011  3.6L V6
Chevrolet  Camaro  2011  6.2L V8
Chevrolet  Camaro  1980  229ci V6
Chevrolet  Camaro  1980  267ci V8
Chevrolet  Camaro  1980  305ci V8
Cadillac   CTS     2004  3.6L V6
Vauxhall   Astra   1979  1.3L
Vauxhall   Astra   1979  1.6L
Vauxhall   Astra   1979  1.8L
Opel       Astra   1979  1.5L
Opel       Astra   1979  2.0L

Es sollte klar sein, dass der einzige mögliche Schlüssel {Marke, Modell, Baujahr, Motor} ist. Diese Tabelle ist also ein reiner Schlüssel und hat keine Attribute, die keine Primzahlen sind.

Um "Lookup"-Tabellen als Datenbeschränkungen hinzuzufügen, reicht es nicht aus, zu sagen, dass man in der ersten Spalte aus {Ford, Chevrolet, Cadillac, Vauxhall, Opel} und in der zweiten Spalte aus {F-150, Camaro, CTS, Astra} wählen muss. Die rechte "Lookup"-Tabelle für Marke und Modell enthält sowohl Marke als auch Modell; Sie wählen aus {Ford F-150, Chevrolet Camaro, Cadillac CTS, Vauxhall Astra, Opel Astra}. (In diesem Fall geht es sogar noch weiter, siehe die Tabelle model_years unten).

create table makes (
  make varchar(25) primary key
);

insert into makes values
('Ford'),
('Chevrolet'),
('Cadillac'),
('Vauxhall'),
('Opel');

create table models (
  make varchar(25) not null references makes (make),
  model varchar(25) not null,
  primary key (make, model)
);

insert into models values 
('Ford', 'F-150'),
('Chevrolet', 'Camaro'),
('Cadillac', 'CTS'),
('Vauxhall', 'Astra'),
('Opel', 'Astra');

create table model_years (
  make varchar(25) not null,
  model varchar(25) not null,
  year integer not null check (year between 1900 and 2050),
  primary key (make, model, year),
  foreign key (make, model) references models (make, model)
);

insert into model_years values
('Ford', 'F-150', 2012),
('Ford', 'F-150', 2011),
('Chevrolet', 'Camaro', 2012),
('Chevrolet', 'Camaro', 2011),
('Chevrolet', 'Camaro', 1980),
('Cadillac', 'CTS', 2004),
('Vauxhall', 'Astra', 1979),
('Opel', 'Astra', 1979);

create table model_year_engines (
  make varchar(25) not null,
  model varchar(25) not null,
  year integer not null,
  engine varchar(25) not null,
  primary key (make, model, year, engine),
  foreign key (make, model, year) references model_years (make, model, year)
);

insert into model_year_engines values
('Ford', 'F-150', 2012, '3.7L V6'),
('Ford', 'F-150', 2012, '3.5L V6 EcoBoost'),
('Ford', 'F-150', 2012, '5.0L V8'),
('Ford', 'F-150', 2012, '6.2L V8'),
('Ford', 'F-150', 2011, '3.7L V6'),
('Ford', 'F-150', 2011, '3.5L V6 EcoBoost'),
('Ford', 'F-150', 2011, '5.0L V8'),
('Ford', 'F-150', 2011, '6.2L V8'),
('Chevrolet', 'Camaro', 2012, '3.6L V6'),
('Chevrolet', 'Camaro', 2011, '3.6L V6'),
('Chevrolet', 'Camaro', 2011, '6.2L V8'),
('Chevrolet', 'Camaro', 1980, '229ci V6'),
('Chevrolet', 'Camaro', 1980, '267ci V8'),
('Chevrolet', 'Camaro', 1980, '305ci V8'),
('Cadillac', 'CTS', 2004, '3.6L V6'),
('Vauxhall', 'Astra', 1979, '1.3L'),
('Vauxhall', 'Astra', 1979, '1.6L'),
('Vauxhall', 'Astra', 1979, '1.8L'),
('Opel', 'Astra', 1979, '1.5L'),
('Opel', 'Astra', 1979, '2.0L');

Kein Motor kann in diese Tabelle aufgenommen werden, wenn seine Zeile nicht zuerst in model_years vorhanden ist. Kein Jahr kann in model_years aufgenommen werden, wenn die entsprechende Zeile nicht zuerst in models vorhanden ist. Und keine Zeile kann in "models" aufgenommen werden, wenn die Zeile nicht zuerst in "makes" vorhanden ist.

Sie können ein gutes Argument für die Verwendung von ON UPDATE CASCADE in einem Schema wie diesem. Es gibt auch gute Argumente dafür, sie nicht zu verwenden. Oracle unterstützt nicht ON UPDATE CASCADE Das ist ein Grund, warum man in Oracle-Tabellen ID-Nummern sieht und warum man manchmal sagt: "Primärschlüsselwerte müssen niemals ändern."

Dies sind die Arten von Tabellen, die Sie benötigen, um Ihre bekannten Anforderungen umzusetzen.

0voto

IAmTimCorey Punkte 15917

Die PK/FK-Beziehung ist eine wirklich starke Beziehung, die Ihnen Möglichkeiten in Ihrer Datenbank eröffnet. Allerdings ist sie nicht immer angemessen. Vieles hängt von der Datenbank ab und davon, wie Sie sie nutzen wollen. Eine einzige Tabelle für die oben genannten Daten ermöglicht einen schnelleren Datenzugriff und eine einfachere Berichterstattung, aber sie geht zu Lasten der Skalierbarkeit und der Datenspeicherung in einer einzigen Instanz.

In Ihrem speziellen Fall würde ich vorschlagen, die Jahre wieder in die Haupttabelle aufzunehmen. Da das Jahr ein int ist, ist die Duplizierung keine große Sache. Ich würde auch sagen, dass Sie wahrscheinlich Ihre Tabelle Modelle mit Ihrer Tabelle Marken verknüpfen sollten, da die Marken mit den Modellen verbunden sind.

0voto

radarbob Punkte 4835

Auf den ersten Blick halte ich all diese Tabellen für sinnlos. Vielleicht MakesModelsAndYears ist alles, was Sie brauchen. Und dann würde ich den Namen noch einmal überdenken. Zumindest würde ich das "Und" weglassen. Bestenfalls würde ich es in "Cars" umbenennen.

Tabellenschlüssel und Datenverknüpfungen

Das ist nicht unbedingt dasselbe. Ein Primärschlüssel identifiziert die Zeilen einer bestimmten Tabelle eindeutig. Das ist alles. Ein Fremdschlüssel ist eine "Garantie" dafür, dass ein bestimmter Wert in einer anderen Tabelle existiert. Daten können durch andere als formal definierte Schlüssel miteinander verbunden sein. Wir nennen diese manchmal Kandidatenschlüssel. Oh, es gibt kein Gesetz, das besagt, dass man in jeder Tabelle einen Primärschlüssel haben muss.

Ich habe mit Datenbanken gearbeitet, in denen ich Tabellen oft mit anderen als Primär- und/oder Fremdschlüsseln verbunden habe. So haben sich die tatsächlichen Datenbeziehungen ergeben.

Normalisierung von Daten

In der Regel sollten Sie Daten vermeiden Redundanz über Tabellen hinweg. Wenn jedoch Ihr Years Tabellenzeile nur eine Spalte - "Jahr" - hat, wozu ist sie dann gut (das gilt auch für die anderen Tabellen)? Sie duplizieren diese Daten im Wesentlichen in MakeModelsAndYears und zeigt auf sie.

Und wenn Sie die Model , Engine , Year , Makes Tabellen machen nicht die dumm, blödsinnig Fehler bei der Erstellung der Spalte "ID" in Ihrer Makes Tabelle (dito für alle Tabellen), nur damit Sie "Chevrolet" nicht in der MakeModelAndYears Tisch. Stellen Sie sich vor, Sie schauen auf die Tabelle und sehen nur Zahlen in einer Zeile nach der anderen!!! Zur Anzeige sinnvoller Informationen müssen Sie eine Menge Joins machen - nur um "1960 Chevy 454 Hemi Impala" zu sagen. Nun, das ist ineffizient!

Indizes

Welche Indizes Sie erstellen, hängt davon ab, wie Sie die Daten abrufen und welche Leistung die Datenbank dabei erbringt.

Erstellen Sie Indizes insbesondere für die Spalten, die Sie möglicherweise verknüpfen oder durchsuchen wollen, die aber keine formalen Schlüssel sind.

Auch mehrspaltige Indizes eignen sich hervorragend für die Spalten, nach denen Sie häufig gemeinsam suchen. Und die Reihenfolge der Indexspalten ist wichtig. Ich habe einen deutlichen Unterschied festgestellt, wenn ich die Spaltenreihenfolge in einem bestimmten Index einfach umgedreht habe. Das mag bei Ihnen anders sein (Wortspiel beabsichtigt). Und ja, unterschiedlich geordnete Indizes für dieselben Spalten können je nach Tabellengröße, Reihenfolge der Join-Spalten und Häufigkeit der Suchabfragen sinnvoll sein. Sie müssen sich diese Dinge einfach ansehen, wenn Sie Leistungsprobleme haben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X