SQL - Viele-zu-Viele-Tabellenprimärschlüssel

125

Diese Frage wird gestellt, nachdem ein Kommentar in dieser Frage gelesen wurde:

Datenbank Design

Wenn Sie eine Viele-zu-Viele-Tabelle erstellen, sollten Sie einen zusammengesetzten Primärschlüssel für die beiden Fremdschlüsselspalten erstellen oder einen automatisch inkrementierten Ersatz-Primärschlüssel "ID" erstellen und einfach Indizes für Ihre beiden FK-Spalten (und möglicherweise) erstellen eine einzigartige Einschränkung)? Was sind die Auswirkungen auf die Leistung beim Einfügen neuer Datensätze / beim erneuten Indizieren?

Grundsätzlich ist dies:

PartDevice
----------
PartID (PK/FK)
DeviceID (PK/FK)

gegen dieses:

PartDevice
----------
ID (PK/auto-increment)
PartID (FK)
DeviceID (FK)

Der Kommentator sagt:

Wenn Sie die beiden IDs zur PK machen, wird die Tabelle in dieser Reihenfolge physisch auf der Festplatte sortiert. Wenn wir also (Teil1 / Gerät1), (Teil1 / Gerät2), (Teil2 / Gerät3) einfügen, muss die Datenbank (Teil 1 / Gerät3) die Tabelle auseinander brechen und die letzte zwischen den Einträgen 2 und 3 einfügen Bei vielen Datensätzen wird dies sehr problematisch, da bei jedem Hinzufügen Hunderte, Tausende oder Millionen von Datensätzen gemischt werden. Im Gegensatz dazu ermöglicht eine automatisch inkrementierende PK, dass die neuen Datensätze bis zum Ende angeheftet werden.

Der Grund, den ich frage, ist, dass ich immer geneigt war, den zusammengesetzten Primärschlüssel ohne Ersatz-Auto-Inkrement-Spalte zu erstellen, aber ich bin mir nicht sicher, ob der Ersatzschlüssel tatsächlich leistungsfähiger ist.

Andy White
quelle
Hier ist eine Silimar-Frage, die auf SO gepostet wurde: stackoverflow.com/questions/344068/…
Tony
(Versucht, dies zu meinem vorherigen Kommentar hinzuzufügen, kann dies aber nicht.) Abhängig von der Anzahl der Einfügungen können Sie Ihren Index auch regelmäßig neu erstellen, um sicherzustellen, dass er schnell Ergebnisse liefert. In SQL Server können Sie auch den FILLFACTOR des Index optimieren, um genügend Platz für Einfügungen bereitzustellen, bevor Daten verschoben werden müssen.
Tony
1
Hängt die Antwort darauf nicht davon ab, welches DBMS verwendet wird? Ich vermute, MySQL wird sich in diesem Fall anders verhalten, SQL-Server etwas
anders
Vorsichtsmaßnahme: Ohne ein bestimmtes Datenbank-Tag ist vieles, was hier gesagt wird, verdächtig. Unterschiedliche Motoren arbeiten unterschiedlich!
Rick James

Antworten:

85

Bei einer einfachen zweispaltigen Viele-zu-Viele-Zuordnung sehe ich keinen wirklichen Vorteil darin, einen Ersatzschlüssel zu haben. Das Aktivieren eines Primärschlüssels (col1,col2)ist garantiert eindeutig (vorausgesetzt, Ihre col1und die col2Werte in den Tabellen, auf die verwiesen wird, sind eindeutig), und ein separater Index (col2,col1)aktiviert die Fälle, in denen die entgegengesetzte Reihenfolge schneller ausgeführt wird. Der Ersatz ist Platzverschwendung.

Sie benötigen keine Indizes für die einzelnen Spalten, da die Tabelle immer nur zum Zusammenfügen der beiden referenzierten Tabellen verwendet werden sollte.

Dieser Kommentar, auf den Sie sich in der Frage beziehen, ist meiner Meinung nach die verwendeten Elektronen nicht wert. Es hört sich so an, als ob der Autor der Meinung ist, dass die Tabelle in einem Array gespeichert ist und nicht in einer ausgeglichenen Mehrwegbaumstruktur mit extrem hoher Leistung.

Zunächst ist es nie notwendig , nur den Index zu speichern oder an der Tabelle zu sortieren. Und der Index wird nicht nacheinander gespeichert , sondern auf effiziente Weise, um schnell abgerufen werden zu können.

Darüber hinaus wird die überwiegende Mehrheit der Datenbanktabellen weitaus häufiger gelesen als geschrieben. Das macht alles, was Sie auf der Auswahlseite tun, weitaus relevanter als alles, was Sie auf der Einfügeseite tun.

paxdiablo
quelle
Der letzte Punkt ist keine gute Verallgemeinerung: "Die überwiegende Mehrheit der Datenbanktabellen wird weitaus häufiger gelesen als geschrieben". Ich finde viele Beispiele für assoziative Tabellen, in die sehr oft geschrieben werden muss, z. B. eine Tabelle, die den Kunden mit der Bestellung verbindet.
Benutzer
5
@buffer, ich werde zu diesem Kommentar stehen (technisch gesehen ist es nur eine Verallgemeinerung, wenn ich "alle Tabellen" sage, "große Mehrheit" basiert auf Erfahrung). Denken wir auch an Ihr Beispiel: Eine Bestellung wird einmal erstellt (sie wird möglicherweise gelegentlich aktualisiert, es ist jedoch unwahrscheinlich, dass sich die Schlüssel- / Indexinformationen ändern, um beispielsweise den Bestellstatus zu beeinflussen. Diese Aktualisierungen und Auswahlen müssen jedoch durchgeführt werden Rechnungen auszudrucken oder Managementberichte zu erstellen, wird die ursprüngliche Beilage überwiegen.
paxdiablo
Denken Sie an Amazon - Tausende Bestellungen werden stündlich erstellt.
Benutzer
9
@buffer, ja, aber auch hier wird jede dieser Bestellungen mit ziemlicher Sicherheit viele Male abgefragt , um (zum Beispiel) Verpackungen, Abrechnungen, Statusaktualisierungen, Geschäftsanalysen usw. durchzuführen . Die absolute Anzahl der Erstellungen ist weniger wichtig als das Verhältnis zwischen Erstellungen und Lesen.
Paxdiablo
1
Mein Punkt ist, insertwird wichtig sein, wenn es tausende Male pro Stunde gemacht wird. Sie können es nicht einfach ignorieren, nur weil das Verhältnis von insertzu select<1 ist. In diesem Fall kümmert sich ein Kunde darum, wie viel Zeit es dauert, eine Bestellung aufzugeben.
Benutzer
19

Für Verknüpfungstabellen wird kein Ersatzschlüssel benötigt.

Ein PK on (col1, col2) und ein weiterer eindeutiger Index on (col2, col1) sind alles, was Sie brauchen

Es sei denn, Sie verwenden ein ORM, das Ihr DB-Design nicht bewältigen kann und für Sie diktiert ...

Bearbeiten: Ich habe hier dasselbe geantwortet: SQL: Benötigen Sie einen automatisch inkrementellen Primärschlüssel für Many-Many-Tabellen?

gbn
quelle
3
Möglicherweise ist ein Dups-Index für col2 anstelle eines eindeutigen Index für (col2, col1) in Ordnung. Der Vorteil des zweispaltigen Index besteht darin, dass nur Index-Scans entweder für col2 allein oder sowohl für col1 als auch für col2 möglich sind (obwohl der andere Index für (col1, col2) auch den Fall "beide" behandelt). Der Nachteil ist der zusätzliche Speicherplatz, der für die zusätzliche Säule benötigt wird. Dies ist normalerweise nicht von Bedeutung, daher ist der Rat alles andere als schrecklich. Wenn jedoch col1 und col2 groß oder sehr unterschiedlich groß sind, können Sie Platz sparen, ohne die Leistung zu beeinträchtigen, indem Sie den zweiten Index nur für die kürzere Spalte festlegen.
Jonathan Leffler
@gbn: Der zweite Index für (col2, col1) muss nicht eindeutig sein, oder?
Benutzer
1
Das Setzen eines eindeutigen Index auf (col1, col2), nachdem es bereits eine PK ist, ist völlig überflüssig
Don Cheadle
@mmcrae: wo machen wir das
Gbn
2
@mmcrae: Ihr Kommentar lautet "Setzen eines eindeutigen Index auf (col1, col2) ..". Die Spaltenreihenfolge in einem Index ist wichtig. (col2, col1)ist nicht (col1, col2). Die PK von ist (col1, col2)möglicherweise nicht für alle Abfragen geeignet und generiert Scans. Wenn Sie also umgekehrt sind, wird die Leistung verbessert, da Suchen möglich sind, bei denen col2 besser ist. Zum Beispiel FK-Validierung, wenn die Tabelle mit col2 gelöscht wurde. Der
Kindertisch wird
12

Ein inkrementeller Primärschlüssel kann erforderlich sein, wenn auf die Tabelle verwiesen wird. Möglicherweise enthält die Viele-zu-Viele-Tabelle Details, die mit dem inkrementellen Primärschlüssel aus einer anderen Tabelle abgerufen werden mussten.

beispielsweise

PartDevice
----------
ID (PK/auto-increment)
PartID (FK)
DeviceID (FK)
Other Details

Mit PartDevice.ID als FK ist es einfach, die 'Sonstigen Details' abzurufen. Daher ist die Verwendung eines inkrementellen Primärschlüssels erforderlich.

Jronny
quelle
1
Vielen Dank! Ich kam zu der Antwort, als ich nach fast dem gleichen Szenario suchte, das Sie beschrieben haben. Aber Sie haben sich von Ihrem ersten Satz entfernt, indem Sie "Andere Details" hinzugefügt haben. Was wäre, wenn ich viele zu viele Zuordnungstabellen hätte, auf die ich aus einer anderen Tabelle verweisen muss? Das heißt, die Viele-zu-Viele-Zuordnungstabelle hat keine anderen Informationen gespeichert ... Wäre die zusätzliche ID-Spalte überhaupt sinnvoll? Wenn nicht, wie wird stattdessen auf einen Datensatz der Zuordnungstabelle verwiesen?
Misanthrop
Hier gibt es zwei Möglichkeiten: Sie können den zusammengesetzten Schlüssel als Fremdschlüssel aus Ihrer Referenzierungstabelle verwenden (dies fügt Ihrer neuen Tabelle eine zusätzliche Spalte hinzu), oder Sie können der Zuordnungstabelle eine ID-Spalte erstellen und eine eindeutige Einschränkung für die ursprüngliche Verbindung festlegen Primärschlüssel, während die neue ID-Spalte zum Primärschlüssel wird.
Vočko
6

Der kürzeste und direkteste Weg, wie ich Ihre Frage beantworten kann, besteht darin, zu sagen, dass die Leistung beeinträchtigt wird, wenn die beiden von Ihnen verknüpften Tabellen keine sequentiellen Primärschlüssel haben. Wie Sie angegeben / zitiert haben, wird der Index für die Verknüpfungstabelle entweder fragmentiert oder das DBMS arbeitet härter, um Datensätze einzufügen, wenn die Verknüpfungstabelle keinen eigenen sequentiellen Primärschlüssel hat. Dies ist der Grund, warum die meisten Leute einen sequentiell inkrementierenden Primärschlüssel in Verknüpfungstabellen einfügen.

Bernhard Hofmann
quelle
2

Wenn also die EINZIGE Aufgabe darin besteht, die beiden Tabellen zu verknüpfen, ist die zweispaltige PK die beste PK.

Wenn es jedoch anderen Zwecken dient, fügen Sie einen weiteren NDX als PK mit einem Fremdschlüssel und einem zweiten eindeutigen Index hinzu.

Index oder PK ist der beste Weg, um sicherzustellen, dass keine Duplikate vorhanden sind. Mit PK können Tools wie Microsoft Management Studio einen Teil der Arbeit (Erstellen von Ansichten) für Sie erledigen

Michael Kosak
quelle