2009-05-19 18 views
17

Ich schaute mir einen Screencast an, in dem der Autor sagte, dass es nicht gut sei, einen Primärschlüssel auf einer Join-Tabelle zu haben, aber warum nicht.Warum ist es nicht gut, einen Primärschlüssel für eine Join-Tabelle zu haben?

In der Join-Tabelle im Beispiel wurden zwei Spalten in einer Rails-Migration definiert, und der Autor fügte jeder Spalte einen Index, jedoch keinen Primärschlüssel hinzu.

Warum ist es nicht gut, in diesem Beispiel einen Primärschlüssel zu haben?

create_table :categories_posts, :id => false do |t| 
    t.column :category_id, :integer, :null => false 
    t.column :post_id, :integer, :null => false 
end 
add_index :categories_posts, :category_id 
add_index :categories_posts, :post_id 

EDIT: Wie ich zu Cletus erwähnt, ich den potenziellen Nutzen eines Autonummernfeld als Primärschlüssel verstehen können sogar für einen Tisch kommen. In dem Beispiel, das ich oben aufgeführt habe, vermeidet der Autor ausdrücklich, ein Auto-Nummernfeld mit der Syntax ": id => false" in der Anweisung "create table" zu erstellen. Normalerweise würde Rails automatisch ein Nummernfeld mit automatischer Nummer zu einer Tabelle hinzufügen, die in einer solchen Migration erstellt wurde, und dies würde der Primärschlüssel werden. Aber für diese Join-Tabelle hat der Autor das konkret verhindert. Ich war mir nicht sicher, warum er sich entschied, diesem Ansatz zu folgen.

+0

Für Redakteure: Es kann wichtig sein, den Kontext dieser Frage zu betonen. Es ist meistens schlechte Form, keinen Primärschlüssel zu haben. –

+0

Guter Artikel ist Codds 1970 Papier http://www.seas.upenn.edu/~zives/03f/cis550/codd.pdf –

+0

Eine Sache zu betrachten, dass Papier 1970 geschrieben wurde, als I/O und Datenspeicherung war relativ viel, viel teurer. In der heutigen Zeit sind die Kosten für das Hinzufügen einer zusätzlichen Primärschlüsselspalte jedoch fast immer gering. Ich würde es lieben, jemanden zu sehen, der einen realen Fall darstellt, bei dem die zusätzliche Spalte ein messbares Problem verursacht. – DGM

Antwort

38

Einige Anmerkungen:

  1. Die Kombination von category_id und post_id ist in der sich eindeutig, so dass eine zusätzliche ID-Spalte ist überflüssig und verschwenderisch
  2. Der Ausdruck „nicht gut, einen Primärschlüssel zu haben“ ist falsch im Screencast. Sie haben immer noch einen Primärschlüssel - er besteht nur aus den zwei Spalten (zB CREATE TABLE foo (cid, pid, PRIMÄRSCHLÜSSEL (cid, pid)). Für Leute, die es gewohnt sind, ID-Werte überall anzuheften, mag das scheinen ungerade, aber in der relationalen Theorie ist es ganz richtig und natürlich, der Screencast-Autor hätte besser gesagt, es sei "nicht gut, ein implizites ganzzahliges Attribut mit dem Namen 'ID' als Primärschlüssel zu haben."
  3. Es ist überflüssig, das Extra zu haben Spalte, weil Sie einen eindeutigen Index auf die Kombination von category_id und post_id setzen, um sicherzustellen, dass keine doppelten Zeilen eingefügt werden.
  4. Schließlich, obwohl allgemeine Nomenklatur ist es einen "zusammengesetzten Schlüssel" nennen, ist dies auch redundant. Der Begriff "Schlüssel" In der relationalen Theorie ist eigentlich die Menge von null oder mehr Attributen, die die Zeile eindeutig identifizieren, also ist es in Ordnung zu sagen, dass der Primärschlüssel die Kategorie ist y_id, post_id
  5. Platzieren Sie die Spalte MOST SELECTIVE in der Deklaration des Primärschlüssels. Eine Diskussion der Konstruktion von b (+/*) Bäumen ist nicht Gegenstand dieser Antwort (für einige untergeordnete Diskussionen siehe: http://www.akadia.com/services/ora_index_selectivity.html), aber in Ihrem Fall würden Sie es wahrscheinlich post_id, category_id seit post_id wollen in der Tabelle weniger häufig auftauchen und so den Index nützlicher machen. Da die Tabelle so klein ist und der Index im Wesentlichen die Datenzeilen ist, ist dies natürlich nicht sehr wichtig. In größeren Fällen wäre der Tisch breiter.
+0

Diese Erklärung traf alle Unklarheiten, an denen ich festhielt. Vielen Dank. "Der Screencast - Autor hätte besser gesagt, es sei nicht gut, ein implizites Integer - Attribut mit dem Namen 'ID' als Primärschlüssel zu haben. '" Und danke, dass du das geschrieben hast: "Es ist überflüssig, die zusätzliche Spalte zu haben, weil du eine eindeutiger Index für die Kombination von category_id und post_id, um sicherzustellen, dass keine doppelten Zeilen eingefügt werden. " –

+0

Es ist nicht korrekt, null oder mehr zu sagen (grundlegende Mengenlehre beiseite), siehe: http://www.seas.upenn.edu/~zives /03f/cis550/codd.pdf –

+0

OK, es ist in der relationalen Theorie (leerer Satz als Schlüssel) OK, aber NICHT in SQL –

3

Ein DBA würde Ihnen sagen, dass der Primärschlüssel in diesem Fall eigentlich die Kombination der beiden FK-Spalten ist. Da Rails/ActiveRecord nicht mit Composite-PKs (standardmäßig mindestens) kompatibel ist, kann dies der Grund sein.

+0

Wenn du "standardmäßig" sagst, meinst du, es gibt eine Möglichkeit, Rails schön zu spielen, aber es ist kompliziert zu machen? –

+0

q-Tipp: Werfen Sie einen Blick auf has_and_belongs_to_many (zusammen mit has_many_through) http://blog.hasmanythrough.com/2007/1/15/basic-rails-association-cardinality - es wird magisch (sorta) nutzen den Beitritt Tabelle –

+0

@po Ich habe * gehört *, dass es Plugins gibt, um AR mit natürlichen Schlüsseln (einschließlich zusammengesetzten Schlüsseln) anstelle von Ersatzschlüsseln arbeiten zu lassen. Ich weiß nicht, ob sie funktionieren oder nicht. –

3

Die Kombination von Fremdschlüsseln kann ein Primärschlüssel sein (sogenannter zusammengesetzter Primärschlüssel). Persönlich bevorzuge ich stattdessen einen technischen Primärschlüssel (Auto-Nummernfeld, Sequenz usw.). Warum? Nun, es macht es viel einfacher, den Datensatz zu identifizieren, den Sie tun müssen, wenn Sie es löschen möchten.

Denken Sie darüber nach: Wenn Sie eine Webpage aller Verknüpfungen präsentieren möchten, ist es viel einfacher, einen Primärschlüssel zur Identifizierung des Datensatzes zu haben.

+0

Ich sehe, was Sie über die Nützlichkeit eines Auto-Nummer-Felds als Primärschlüssel auch für eine Join-Tabelle meinen. In dem Beispiel, das ich oben aufgeführt habe, vermeidet der Autor ausdrücklich, ein Auto-Nummernfeld mit der Syntax ": id => false" in der create table-Anweisung zu erstellen. Normalerweise würde Rails automatisch ein Nummernfeld mit automatischer Nummer zu einer Tabelle hinzufügen, die in einer solchen Migration erstellt wurde, und dies würde der Primärschlüssel werden. Aber für diese Join-Tabelle hat der Autor das konkret verhindert. Ich war mir nicht sicher, warum er sich entschied, diesem Ansatz zu folgen. –

3

Grundsätzlich, weil es nicht nötig ist. Die Kombination der zwei Fremdschlüsselfelder identifiziert jede Zeile ausreichend eindeutig.

Aber das sagt nur, warum es keine gute Idee ist .... aber warum sollte es eine schlechte Idee sein?

Betrachten Sie den Overhead Hinzufügen einer Identität Spalte hinzufügen würde. Die Tabelle würde 50% mehr Speicherplatz belegen. Schlimmer ist die Indexsituation. Bei einem Identitätsfeld müssen Sie die Identitätsanzahl sowie einen zweiten Index pflegen. Sie verdreifachen den Speicherplatz und verdreifachen die Arbeit, die bei jedem Einsatz ausgeführt werden muss. Der einzige Vorteil ist eine etwas kürzere WHERE-Klausel in einem DELETE-Befehl.

Auf der anderen Seite, wenn die zusammengesetzten Schlüsselfelder die gesamte Tabelle sind, dann kann der Index die Tabelle sein.

+1

Alle Primärschlüssel sind keine Identitätsspalten! –

+0

Entschuldigung. Ich habe dich bis zum letzten Satz verfolgt. Ich habe nicht verstanden, was Sie damit meinten: "Andererseits, wenn die zusammengesetzten Schlüsselfelder die gesamte Tabelle sind, dann kann der Index die Tabelle sein." –

+0

q-tip: Es gibt keinen Vorteil, einen Index hinzuzufügen, der der gesamten Tabelle entspricht, wie dies der Fall wäre, wenn Ihr Primärschlüssel ein zusammengesetzter Schlüssel wäre, der aus jeder Spalte in der Tabelle besteht. Wenn wir dies tun, dient die Tabelle als Index. Ich hoffe, dass das nützlich ist. Entschuldigung, wenn es nicht ist. –

3

Es ist eine schlechte Idee, keinen Primärschlüssel in einer Tabelle zu haben, Punkt (wenn das DBMS ein relationales DBMS - oder ein SQL DBMS ist). Primärschlüssel sind ein entscheidender Teil der Integrität Ihrer Datenbank.

Ich nehme an, wenn es Ihnen nichts ausmacht, dass Ihre Datenbank ungenau ist und immer wieder falsche Antworten liefert, dann könnten Sie verzichten ... aber die meisten Leute wollen genaue Antworten von ihrem DBMS und für solche Leute sind Primärschlüssel entscheidend .

+0

Welche Art von ungenauen Daten würde ein Primärschlüssel in dieser aus zwei Spalten bestehenden Join-Tabelle verhindern? Ich zweifle nicht daran, dass Sie Recht haben, aber ich verstehe einfach nicht, welche Art von ungültigen Daten hier möglich ist. Kannst du mir ein Beispiel geben? –

+0

Doppelte Reihen, stelle ich mir vor. –

+0

Doppelte Zeilen habe ich mir vorgenommen. Sie können auch andere Beispiele finden, vor allem mit großzügig verstreuten Identitätsspalten und keinen eindeutigen Einschränkungen für die natürlichen Schlüssel. Wenn die Tabelle andere Spalten als nur die Schlüsselspalten hat, können Sie die Datenbank tatsächlich mit Widersprüchen versehen - und wenn Sie klassische Logik kennen, wissen Sie, dass das Argumentieren aus einem Widerspruch zu Irrtümern führt. –

1

Pros eine einzelne PK mit identifiziert

  • eine Zeile eindeutig mit einem einzelnen Wert
  • macht es leicht, die Beziehung von anderswo zu verweisen, wenn nötig
  • Einige Tools wollen Sie haben einen einzelnen ganzzahligen Wert pk

Nachteile von

  • Benötigt mehr Speicherplatz
  • Need 3 Indizes statt 1
  • Ohne eine eindeutige Einschränkung eines einzigen PK mit Sie mit mehreren Zeilen für die gleiche Beziehung
könnte am Ende

Hinweise

  • Sie müssen eine eindeutige Einschränkung definieren, wenn Sie Duplikate vermeiden möchten
  • Meiner Meinung nach verwenden Sie nicht die einzelnen pk, wenn Sie Tabelle wird riesig sein, andernfalls Handel ein wenig Speicherplatz für die Bequemlichkeit. Ja, es ist verschwenderisch, aber wen interessiert ein paar MB auf der Festplatte in realen Anwendungen.
+0

"Benötigen Sie 3 Indizes statt 1" - Ich nehme an, Sie meinen den Primärschlüssel in einem Auto-Nummernfeld plus die beiden anderen Indizes in meinem obigen Beispiel (nicht zwei zusätzliche Indizes, die in meinem Beispiel nicht aufgeführt sind). "Ohne eine eindeutige Einschränkung könnten Sie mehrere Zeilen für dieselbe Beziehung haben" -> In diesem Fall müsste der PK also auf die beiden Spalten in dieser Join-Tabelle verweisen. Mit anderen Worten, ein Primärschlüssel, der einfach aus einem Auto-Nummernfeld besteht, würde nicht funktionieren. Ich hoffe, ich verstehe. –

2

Das Platzieren der selektivsten Spalte sollte nur in der INDEX-Deklaration relevant sein.In der KEY-Deklaration sollte es keine Rolle spielen (weil, wie richtig ausgeführt wurde, der KEY ein SET ist und innerhalb einer Menge die Reihenfolge keine Rolle spielt - die Menge {a1, a2} ist dieselbe Menge wie {a2 , a1}).

Wenn ein DBMS-Produkt so beschaffen ist, dass die Anordnung von Attributen in einer KEY-Deklaration einen Unterschied macht, dann ist dieses DBMS-Produkt nicht in der Lage, zwischen dem logischen Entwurf einer Datenbank (dem Teil, wo Sie die KEY-Deklaration durchführen) und das physische Design der Datenbank (der Teil, in dem Sie die INDEX-Deklaration durchführen).

+0

Die meisten, wenn nicht alle DBMS-Produkte, die ich verwendet habe (MySQL, Sybase ASE, SQL Server, Oracle), erstellen implizit einen eindeutigen Index für die PRIMARY KEY-Deklaration in der von Ihnen angegebenen Reihenfolge. Ja, es verletzt die logische/physische Unabhängigkeit, aber es ist der einzige Weg zu gehen (es sei denn, Sie erstellen die Tabelle w/o einen Primärschlüssel, erstellen einen eindeutigen Index, dann markieren Sie den Primärschlüssel irgendwie) –

+0

Außerdem verletzt SQL per Definition einen TON des relationalen Modells, dies beinhaltete: D –

2

Ich wollte den folgenden Kommentar kommentieren: "Es ist nicht richtig, null oder mehr zu sagen".

Ich wollte bemerken, dass der Text, dem dieser Kommentar hinzugefügt wurde, einfach nicht den Text "Null oder mehr" enthielt, so der Autor des Kommentars, den ich kommentieren wollte, kritisierte jemand anderes für etwas, das nicht hatte wurde gesagt.

Ich wollte auch kommentieren, dass es nicht richtig ist zu sagen, dass es nicht richtig ist, sagen "Null oder mehr". Die Relationstheorie, wie sie heute unter den wenigen Menschen bekannt ist, die immer noch versuchen, die Details dieser Theorie zu studieren, ERFORDERT tatsächlich die Möglichkeit eines Schlüssels ohne Attribute.

Aber als ich den Knopf "Kommentar" drückte, antwortete mir das System, dass das Kommentieren eine Reputationsbewertung von 50 (oder etwas Ähnliches) erfordert.

Eine traurige Illustration, wie die Welt vergessen zu haben scheint, dass Wissenschaft keine Demokratie ist, und dass in der Wissenschaft die Wahrheit nicht von jemandem bestimmt wird, der die Mehrheit hat oder von wem auch immer "genügend Ruf" hat.

+0

Ich sehe - das Datenbank-Dictionary des Datums erneut lesen sagt, dass eine leere PK verwendet wird, um Relvars auf eine einzelne Zeile zu beschränken. OK, ich kaufe das - es ist nicht explizit in Codds Schreibweise, aber anders als in diesem begrenzten Fall, wann würde jemand einen leeren Schlüssel benutzen? –