Soll ich transitive Fremdschlüssel hinzufügen?

11

Einfaches Beispiel: Es gibt eine Kundentabelle.

create table Customers (
  id integer,
  constraint CustomersPK primary key (id)
)

Alle anderen Daten in der Datenbank sollten mit a verknüpft sein Customer, Orderssieht also z. B. so aus:

create table Orders (
  id integer,
  customer integer,
  constraint OrdersPK primary key (customer, id),
  constraint OrdersFKCustomers foreign key (customer) references Customers (id)
)

Angenommen, es gibt jetzt eine Tabelle, die auf Folgendes verweist Orders:

create table Items (
  id integer,
  customer integer,
  order integer,
  constraint ItemsPK primary key (customer, id),
  constraint ItemsFKOrders foreign key (customer, order) references Orders (customer, id)
)

Soll ich einen separaten Fremdschlüssel von Itemsbis hinzufügen Customers?

...
constraint ItemsFKCustomers foreign key (customer) references Customers (id)

Stattdessen ein Bild: Soll ich die gestrichelte Linie / FK hinzufügen?

Einfaches Beispielschema


Bearbeiten: Ich habe den Tabellen Primärschlüsseldefinitionen hinzugefügt. Ich möchte noch einmal auf den Punkt eingehen, den ich oben angesprochen habe: Die Datenbank wird im Grunde genommen von Kunden als Korrektheits- / Sicherheitsmaßnahme isoliert. Daher enthalten alle Primärschlüssel die customerID.

vektor
quelle
2
Nein, das solltest du nicht. Der zusätzliche FK ist nicht erforderlich. Die Einschränkung wird von den beiden anderen FKs erzwungen.
Ypercubeᵀᴹ
@ypercube Gibt es Leistungseinbußen bei einem redundanten FK? Irgendwelche Vorteile, die Sie sich
vorstellen können
1
@vektor, die Leistungsaspekte variieren wahrscheinlich von einem rdbms zum anderen, aber im Allgemeinen erhalten Sie eine Auswirkung auf die Leistung für jeden neuen FK, den Sie hinzufügen, da jedes Einfügen / Aktualisieren / Löschen in einer der PK / FK-Tabellen mit dem verglichen werden muss Zwang. Bei großen PK-Tabellen kann dieser Leistungsverlust sehr schwerwiegend sein.
Daniel Hutmacher

Antworten:

6

Ich denke, das ist die ursprüngliche Idee.

Geben Sie hier die Bildbeschreibung ein

Als Erstes müssen Sie feststellen, dass die PK in der LineItem-Tabelle drei Attribute hat {CustomerID, CustomerOrderNo, OdrerItemNo}, im Gegensatz zu nur zwei in Ihrem Beispiel.

Als zweites ist die Verwirrung zu beachten, die sich aus der Verwendung des generischen idNamens für ein Attribut ergibt .

Das CustomerOrderNosollte idealerweise (1,2,3 ..) für jeden Kunden und OrderItemNo(1,2,3 ...) für jede Bestellung sein.

Nun, das ist nett, wenn möglich, erfordert aber eine Abfrage, die nach dem vorherigen Maximalwert sucht, wie z

select max(CustomerOrderNo)
from Order 
where CustomerID = specific_customer ; 

Dies wird in Umgebungen mit hohem Transaktionsvolumen häufig nicht bevorzugt. Daher werden diese häufig durch ein automatisches Inkrement ersetzt, das im Wesentlichen demselben Zweck dient. Es ist wahr, dass dieses Auto-Inkremet jetzt einzigartig ist, daher kann es als SCHLÜSSEL verwendet werden - aber Sie können es als notwendigen Kompromiss für das betrachten OrderItemNo.

Mit etwas Umbenennung CustomerOrderNo -> OrderNound OrderItemNo-> können ItemNoSie zu diesem Modell gelangen

Geben Sie hier die Bildbeschreibung ein

Wenn Sie sich nun OrderFolgendes ansehen, sind die folgenden einzigartig

{OrderNo}             -- PK
{CustomerID, OrderNo} -- superkey,  AK on the diagram.

Beachten Sie, dass dies {CustomerID, OrderNo}an die weitergegeben wird LineItem, um als FK zu dienen.

Wenn Sie ein wenig blinzeln, ist dies in der Nähe Ihres Beispiels, jedoch PKs {ItemNo} and {OrderNo}nur mit - im Gegensatz zu zwei Spalten-PKs aus Ihrem Beispiel.

Die Frage ist nun, warum nicht zu so etwas vereinfachen?

Geben Sie hier die Bildbeschreibung ein

Welches ist in Ordnung, aber einleitet Wegabhängigkeit - Sie nicht teilnehmen können LineItemmit Customerdirekt müssen, verwenden Sie Orderin der Verknüpfung.


Ich bevorzuge den ersten Fall, wenn möglich - Sie wählen Ihren Favoriten. In diesen drei Fällen ist natürlich keine direkte FK von LineItembis erforderlich Customer.

Damir Sudarevic
quelle
Ich habe mich umgesehen, aber ich kann nicht sehen, dass "Pfadabhängigkeit" als weit verbreiteter Begriff für das verwendet wird, was ich als "transitive Beziehung 2. Grades" bezeichnen würde (obwohl meine Terminologie wahrscheinlich auch falsch ist)
Dai
2

Der "Artikel" sollte nicht direkt auf den "Kunden" verweisen, da dies durch die "Bestellung" des Artikels impliziert wird. Sie benötigen also überhaupt nicht die Spalten "Kunde" in der Tabelle "Artikel".

Die Beziehung des Artikels zum Kunden wird mit dem vorhandenen Fremdschlüssel sichergestellt.

Wenn orders.id eine Identitätsspalte ist, sollten Sie items.customer insgesamt entfernen.

Daniel Hutmacher
quelle
1
Danke, ich habe nicht bemerkt, dass "Kunde" auch in der ersten FK von "Artikel" bis "Bestellungen" enthalten war. Ich habe meine Antwort entsprechend ausgearbeitet.
Daniel Hutmacher
@ DanielHutmacher Ich habe die Frage so bearbeitet, dass sie Primärschlüssel meiner Tabellen enthält. Dies erklärt die seltsamen FKs, die Sie in Ihrer Bearbeitung erwähnen.
Vektor
Ok, ich habe meine Antwort aktualisiert. :)
Daniel Hutmacher
Ich customervermute, dass es ein ungewöhnlicher Ansatz ist , alle Tabellen zu haben (und damit die DB zu silieren). Ich muss gestehen, dass es nur etwas ist, was ich in meiner vorherigen Arbeit gesehen habe. Macht es für dich Sinn? Haben Sie so ein Design schon einmal gesehen?
Vektor
Ich würde sagen, es sieht aus wie ein Datawarehouse-Ansatz (Sternschema), bei dem Sie Daten absichtlich denormalisieren möchten, um Verknüpfungen zu vermeiden. Oder der Primärschlüssel kann zusammengesetzt sein, dh die erste, zweite, dritte Bestellung von Kunde A, die erste, zweite Bestellung von Kunde B usw. - wenn die Spalte mit der Bestell-ID allein nicht eindeutig ist.
Daniel Hutmacher