zusammengesetzte Primärschlüssel sind eine schlechte Praxis? [geschlossen]

14

Ich möchte wissen, ob zusammengesetzte Primärschlüssel eine schlechte Praxis sind und wenn nicht, in welchen Szenarien die Verwendung empfohlen wird.

Meine Frage basiert auf diesem Artikel

Designfehler bei Datenbanken

Der Teil über zusammengesetzte Primärschlüssel:

Schlechte Praxis Nr. 6: Zusammengesetzte Primärschlüssel

Dies ist eine Art kontroverser Punkt, da viele Datenbankdesigner heutzutage davon sprechen, ein automatisch generiertes Feld mit ganzzahliger ID als Primärschlüssel anstelle eines zusammengesetzten Felds zu verwenden, das durch die Kombination von zwei oder mehr Feldern definiert wird. Dies wird derzeit als „Best Practice“ definiert, und ich persönlich stimme dem eher zu.

Bild eines zusammengesetzten Primärschlüssels

Dies ist jedoch nur eine Konvention, und natürlich ermöglichen DBEs die Definition von zusammengesetzten Primärschlüsseln, die viele Designer für unvermeidlich halten. Daher sind zusammengesetzte Primärschlüssel wie bei der Redundanz eine Entwurfsentscheidung.

Beachten Sie jedoch, dass der Index, der den zusammengesetzten Schlüssel steuert, bis zu einem Punkt anwachsen kann, an dem die Leistung der CRUD-Operation stark beeinträchtigt ist, wenn für Ihre Tabelle mit einem zusammengesetzten Primärschlüssel Millionen von Zeilen erwartet werden. In diesem Fall ist es viel besser, einen einfachen Primärschlüssel mit ganzzahliger ID zu verwenden, dessen Index kompakt genug ist, und die erforderlichen DBE-Einschränkungen festzulegen, um die Eindeutigkeit aufrechtzuerhalten.

Hackvan
quelle
4
Dies ist keine "gute" oder "schlechte" Praxis. Jede Entwurfsentscheidung muss einen Zweck erfüllen; Wenn Sie (sich selbst und anderen) erklären können, warum Sie eine zusammengesetzte PK benötigen, können Sie loslegen. Umgekehrt, wenn Sie erklären können, warum Sie es nicht brauchen, können Sie auch loslegen. Der Artikel, auf den Sie verlinken, erklärt meiner Ansicht nach sehr schlecht.
Mustaccio
Dieser Artikel weist auf einen Punkt hin, aber wenn wir beliebte Frameworks (wie z. B. Rails) in seinen "Best Practices" betrachten, werden diese Primärschlüssel nicht unterstützt. Deshalb habe ich gefragt, warum? Es ist für technische Schwierigkeiten oder etwas anderes.
Hackvan
Für die Framework-Designs ist es einfacher, nur "einfache" einspaltige Ganzzahl-Primärschlüssel zu unterstützen. Und da die meisten Entwickler (zumindest nach meiner persönlichen Erfahrung) nicht viel über Datenbankkenntnisse verfügen (zumindest im Verhältnis zu den Benutzern dieser Website), funktioniert dies für die meisten Benutzer der Software gut genug. Da die meisten Benutzer der Software keine zusammengesetzten Schlüssel benötigen (oder zumindest zu Beginn nicht glauben, dass sie diese benötigen), können sie davonkommen, keine (gute) Unterstützung für zusammengesetzte Schlüssel bereitzustellen.
Willem Renzema
1
Wie ist eine GUID besser als ein INTEGER [Serial | Auto_Increment | Identität | <whatever_integer_you_like>]?
Vérace
4
Ich würde diesen Autor nicht einstellen
Paparazzo

Antworten:

31

Zu sagen, dass die Verwendung von "Composite keys as PRIMARY KEY is bad practice"völlig Unsinn ist!

Verbundwerkstoffe PRIMARY KEYsind oft eine sehr "gute Sache" und die einzige Möglichkeit, natürliche Situationen im Alltag zu modellieren!

Denken Sie an das klassische Lehrbeispiel Databases-101 für Studenten und Kurse und an die vielen Kurse, die von vielen Studenten besucht werden!

Erstellen Sie Tabellen Kurs und Schüler:

CREATE TABLE course
(
  course_id SERIAL,
  course_year SMALLINT NOT NULL,
  course_name VARCHAR (100) NOT NULL,
  CONSTRAINT course_pk PRIMARY KEY (course_id)
);


CREATE TABLE student
(
  student_id SERIAL,
  student_name VARCHAR (50),
  CONSTRAINT student_pk PRIMARY KEY (student_id)
);

Ich gebe Ihnen das Beispiel im PostgreSQL-Dialekt (und MySQL ) - sollte für jeden Server mit ein wenig Optimierung funktionieren.

Jetzt wollen Sie natürlich den Überblick behalten , von denen Schüler nehmen , welcher Kurs - so haben Sie , was eine genannt wird joining table(auch genannt linking, many-to-manyoder m-to-nTabellen). Sie sind auch als associative entitieseher im Fachjargon bekannt!

1 Kurs kann viele Studenten haben.
1 Student kann viele Kurse belegen.

Sie erstellen also eine Verbindungstabelle

CREATE TABLE course_student
(
  cs_course_id INTEGER NOT NULL,
  cs_student_id INTEGER NOT NULL,

  -- now for FK constraints - have to ensure that the student
  -- actually exists, ditto for the course.

  CREATE CONSTRAINT cs_course_fk FOREIGN KEY (cs_course_id) REFERENCES course (course_id),
  CREATE CONSTRAINT cs_student_fk FOREIGN KEY (cs_student_id) REFERENCES student (student_id)
);

Die einzige Möglichkeit, diesem Tisch eine sinnvolle Note zu geben, PRIMARY KEYbesteht darin, KEYeine Kombination aus Kurs und Schüler zu erstellen. Auf diese Weise können Sie nicht bekommen:

  • ein Duplikat der Kombination aus Student und Kurs

    • In einem Kurs kann derselbe Student nur einmal eingeschrieben sein

    • Ein Student kann sich nur einmal für denselben Kurs anmelden

  • Sie haben auch eine fertige Suche KEYnach Kurs pro Schüler - AKA ein Deckungsindex ,

  • Es ist trivial, Kurse ohne Studenten und Studenten zu finden, die keine Kurse belegen!

    - Das db-Geige Beispiel hat die PK Einschränkung in die CREATE TABLE gefaltet - Es kann so oder so durchgeführt werden. Ich bevorzuge es, alles in der Anweisung CREATE TABLE zu haben.


ALTER TABLE course_student 
ADD CONSTRAINT course_student_pk 
PRIMARY KEY (cs_course_id, cs_student_id);

Wenn Sie feststellen, dass die Suche nach Schülern nach Kurs langsam war, können Sie ein UNIQUE INDEXon (sc_student_id, sc_course_id) verwenden.

ALTER TABLE course_student 
ADD CONSTRAINT course_student_sc_uq  
UNIQUE (cs_student_id, cs_course_id);

Es gibt kein Allheilmittel Indizes für das Hinzufügen - sie werden machen INSERTs und UPDATEs langsamer, aber im großen Vorteil enorm abnimmtSELECT Zeiten! Es ist in den Entwickler bis zu indizieren ihre Kenntnisse und Erfahrungen gegeben , um zu entscheiden, aber zu sagen , dass Verbund PRIMARY KEYs sind immer schlecht ist schlicht und einfach falsch.

Beim Verbinden von Tabellen sind sie normalerweise die einzigen PRIMARY KEY , die Sinn machen! Das Verbinden von Tabellen ist auch sehr häufig die einzige Möglichkeit zu modellieren, was in der Wirtschaft oder in der Natur oder in praktisch jeder Sphäre passiert, die mir einfällt!

Diese PK ist auch nützlich, covering indexum die Suche zu beschleunigen. In diesem Fall wäre es besonders nützlich, wenn man regelmäßig nach (course_id, student_id) sucht, was, wie man sich vorstellen kann, oft der Fall sein kann!

Dies ist nur ein kleines Beispiel dafür, wo ein Komposit PRIMARY KEYeine sehr gute Idee sein kann und der einzig vernünftige Weg, die Realität zu modellieren! Auf den ersten Blick fällt mir noch viel mehr ein.

Ein Beispiel aus meiner eigenen Arbeit!

Betrachten Sie eine Flugtabelle mit einer Flug-ID, einer Liste der Abflug- und Ankunftsflughäfen und den relevanten Zeiten sowie eine Cabin_crew-Tabelle mit Besatzungsmitgliedern!

Die einzig vernünftige Möglichkeit, dies zu modellieren, besteht darin, eine Flight_Crew-Tabelle mit der Flight_ID und der Crew_ID als Attribut zu haben. Die einzig vernünftige Möglichkeit PRIMARY KEYbesteht darin, den zusammengesetzten Schlüssel der beiden Felder zu verwenden!

Vérace
quelle
2
Im Beispiel von Kurs und Studenten ist es möglich, dass course_student einen idPrimärschlüssel und einen eindeutigen Index hat cs_student_id cs_course_idund dieselben Ergebnisse erzielt.
Hackvan
2
Warum dabei Ressourcen verschwenden? Mit PK (course_id, student_id) haben Sie per Definition bereits einen eindeutigen Index für diese Felder! Ein eindeutiger Index für (student_id, course_id) kann hilfreich sein, um die Suche zu beschleunigen. Sagen Sie, wenn Sie nach Studenten suchen, die keine Kurse belegen, aber diese Entscheidung könnte eine operative Entscheidung sein, aber in diesen Tagen mit relativ billigem Speicher. Ich würde es empfehlen, zumal man denken würde, dass die Tabelle nicht sehr häufig aktualisiert wird.
Vérace
1
Stimmen Sie Link-Tabellen vollständig zu - ich arbeite gerade mit mehreren. Wenn ich jedoch meinen C # -Hut aufsetze, arbeite ich mit dem Reversepoco-Generator und baue nützliche Klassen (Suchen, Speichern usw.) für die nächste Ebene auf. Ich bin auf ein großes Problem gestoßen - zusammengesetzte Schlüssel werden zu einer PITA für generischen Speicher- / Suchcode. Ja, vielleicht könnte ich zu EDMX-Dateien zurückkehren, aber ich muss immer noch entweder den Sonderfallcode umgehen (Pkey-Spalten zählen?) Oder einen künstlichen Ersatzschlüssel hinzufügen (mag keine und benötige zusätzliche Eindeutigkeitsbeschränkungen :(). Also, ich denke Leute, die keine Verbundwerkstoffe mögen, sprechen vom App-Layer-Code.
Richard Griffiths
Abhängig von der Häufigkeit der Einsätze und der Häufigkeit der Indexdefragmenierung im Vergleich zum Wartungsfenster ist dies die bessere Lösung. Bei einigen Designentscheidungen handelt es sich jedoch um Kompromisse, die auf Anforderungen beruhen, die möglicherweise nicht sofort sichtbar sind. Wie in einem Kommentar erwähnt, sollten Sie die Vor- und Nachteile beider Szenarien identifizieren und eine Designentscheidung treffen.
Jonathan Fite
Was passiert, wenn ein Schüler den Kurs wiederholt? Wenn nicht zeitlich getrennte Kurse unterschiedliche IDs erhalten, haben Sie eine weitere Zuordnungstabelle. Oder fügen Sie ein Feld für das Kursdatum hinzu, das jetzt dem Schlüssel hinzugefügt werden muss.
Iheanyi
3

Meine halbherzige Einstellung: Ein "Primärschlüssel" muss nicht der einzige eindeutige Schlüssel sein, der zum Nachschlagen von Daten in der Tabelle verwendet wird, obwohl Datenverwaltungstools ihn als Standardauswahl anbieten. Wenn Sie also auswählen möchten, ob eine Zusammensetzung aus zwei Spalten oder eine zufällig (wahrscheinlich seriell) generierte Nummer als Tabellenschlüssel verwendet werden soll, können Sie zwei verschiedene Schlüssel gleichzeitig verwenden.

Wenn Datenwerte einen geeigneten eindeutigen Begriff enthalten, der die Zeile darstellen kann, würde ich diesen lieber als "Primärschlüssel" deklarieren, auch wenn er zusammengesetzt ist, als einen "synthetischen" Schlüssel zu verwenden. Der synthetische Schlüssel kann aus technischen Gründen eine bessere Leistung erbringen, aber meine eigene Standardauswahl besteht darin, den realen Begriff als Primärschlüssel zu bestimmen und zu verwenden, es sei denn, Sie müssen wirklich den anderen Weg gehen, damit Ihr Service funktioniert.

Ein Microsoft SQL Server verfügt über die eindeutige, aber verwandte Funktion des "Clustered Index", der die physische Speicherung von Daten in Indexreihenfolge steuert und auch in anderen Indizes verwendet wird. Standardmäßig wird ein Primärschlüssel als Clustered-Index erstellt. Sie können jedoch stattdessen Nicht-Clustered auswählen, vorzugsweise nach dem Erstellen des Clustered-Index. Sie können also eine Spalte mit Ganzzahlidentität als Clustered-Index und beispielsweise den Dateinamen nvarchar (128 Zeichen) als Primärschlüssel erstellen. Dies ist möglicherweise besser, da der Clustered-Indexschlüssel eng ist, auch wenn Sie den Dateinamen als Fremdschlüsselbegriff in anderen Tabellen speichern - obwohl dieses Beispiel ein guter Fall ist, um dies auch nicht zu tun.

Wenn Ihr Entwurf das Importieren von Datentabellen umfasst, die einen unbequemen Primärschlüssel zum Identifizieren verwandter Daten enthalten, bleiben Sie ziemlich fest.

https://www.techopedia.com/definition/5547/primary-key beschreibt ein Beispiel für die Auswahl, ob Daten mit der Sozialversicherungsnummer eines Kunden als Kundenschlüssel in allen Datentabellen gespeichert oder eine beliebige Kunden-ID generiert werden sollen registriere sie. Tatsächlich ist dies ein schwerwiegender Missbrauch von SSN, abgesehen davon, ob es funktioniert oder nicht. Es ist ein persönlicher und vertraulicher Datenwert.

Ein Vorteil der Verwendung einer realen Tatsache als Schlüssel besteht darin, dass Sie ohne erneutes Verknüpfen mit der Tabelle "Kunde" Informationen darüber in anderen Tabellen abrufen können - dies ist jedoch auch ein Problem der Datensicherheit.

Außerdem sind Sie in Schwierigkeiten, wenn die SSN oder ein anderer Datenschlüssel falsch aufgezeichnet wurde, sodass Sie den falschen Wert in 20 eingeschränkten Tabellen anstatt nur in "Kunde" haben. Während die synthetische customer_id keine externe Bedeutung hat, kann es sich nicht um einen falschen Wert handeln.

Robert Carnegie
quelle
1
Ich schätze besonders die Beobachtung, dass in Abhängigkeit von Kundendaten als Schlüssel sogar bekannte eindeutige Kundendaten (hier SSN) ausfallen, wenn diese Daten jemals korrigiert werden müssen.
ToolmakerSteve