Was kann der Nachteil sein, wenn immer eine einzelne Ganzzahlspalte als Primärschlüssel verwendet wird?

18

Innerhalb einer Webanwendung, an der ich arbeite, werden alle Datenbankvorgänge mithilfe einiger über Entity Framework ORM definierter generischer Repositorys abstrahiert.

Um jedoch ein einfaches Design für die generischen Repositorys zu haben, müssen alle beteiligten Tabellen eine eindeutige Ganzzahl definieren ( Int32in C #, intin SQL). Bisher war dies immer der PK des Tisches und auch der IDENTITY.

Fremdschlüssel werden häufig verwendet und verweisen auf diese ganzzahligen Spalten. Sie sind sowohl für die Konsistenz als auch für die Generierung von Navigationseigenschaften durch den ORM erforderlich.

Die Anwendungsschicht führt normalerweise die folgenden Vorgänge aus:

  • Erstes Laden der Daten aus der Tabelle (*) -SELECT * FROM table
  • Update -UPDATE table SET Col1 = Val1 WHERE Id = IdVal
  • Löschen -DELETE FROM table WHERE Id = IdVal
  • Einfügen -INSERT INTO table (cols) VALUES (...)

Weniger häufige Operationen:

  • Masseneinfügung - BULK INSERT ... into tablegefolgt von (*) allen Datenladevorgängen (um generierte Bezeichner abzurufen)
  • Massenlöschung - Dies ist eine normale Löschoperation, aus Sicht von ORM jedoch "voluminös":DELETE FROM table where OtherThanIdCol = SomeValue
  • Massenaktualisierung - Dies ist ein normaler Aktualisierungsvorgang, aus Sicht von ORM jedoch "umfangreich":UPDATE table SET SomeCol = SomeVal WHERE OtherThanIdCol = OtherValue

* Alle kleinen Tabellen werden auf Anwendungsebene zwischengespeichert und fast alle SELECTserreichen die Datenbank nicht. Ein typisches Muster ist die Anfangslast und viele INSERTs, UPDATEs und DELETEs.

Aufgrund der aktuellen Anwendungsnutzung ist die Wahrscheinlichkeit sehr gering, dass jemals 100 Millionen Datensätze in einer der Tabellen erreicht werden.

Frage: Gibt es aus Sicht eines Datenbankadministrators erhebliche Probleme, die durch diese Einschränkung des Tabellenentwurfs auftreten können?

[BEARBEITEN]

Nach dem Lesen der Antworten (danke für das großartige Feedback) und der Artikel, auf die verwiesen wird, muss ich weitere Details hinzufügen:

  1. Aktuelle Anwendungsspezifikationen - Ich habe die aktuelle Webanwendung nicht erwähnt, da ich verstehen möchte, ob das Modell auch für andere Anwendungen wiederverwendet werden kann. In meinem speziellen Fall handelt es sich jedoch um eine Anwendung, die viele Metadaten aus einem DWH extrahiert. Quelldaten sind ziemlich unübersichtlich (auf seltsame Weise denormalisiert, haben einige Inkonsistenzen, in vielen Fällen keine natürliche Kennung usw.) und meine App generiert klar getrennte Entitäten. Außerdem werden viele der generierten Bezeichner ( IDENTITY) angezeigt, damit der Benutzer sie als Geschäftsschlüssel verwenden kann. Dies schließt neben einem massiven Code-Refactoring die Verwendung von GUIDs aus .

  2. "Sie sollten nicht die einzige Möglichkeit sein, eine Zeile eindeutig zu identifizieren" (Aaron Bertrand ♦) - das ist ein sehr guter Rat. Alle meine Tabellen definieren auch einen EINZIGARTIGEN KONSTRAINT, um sicherzustellen, dass Geschäftsduplikate nicht zulässig sind.

  3. Front-End-App-gesteuertes Design im Vergleich zum datenbankgesteuerten Design - die Auswahl des Designs wird durch diese Faktoren verursacht

    1. Entity Framework-Einschränkungen - PKs mit mehreren Spalten sind zulässig, ihre Werte können jedoch nicht aktualisiert werden

    2. Benutzerdefinierte Einschränkungen : Durch die Verwendung eines einzelnen Ganzzahlschlüssels werden Datenstrukturen und Nicht-SQL-Code erheblich vereinfacht. Beispiel: Alle Wertelisten haben einen Integer-Schlüssel und einen angezeigten Wert. Noch wichtiger ist, dass jede zum Cachen markierte Tabelle in der Lage ist, eine Unique int key -> valueKarte zu erstellen .

  4. Komplexe Auswahlabfragen - dies wird so gut wie nie vorkommen, da alle kleinen Tabellendaten (<20-30 KB) auf Anwendungsebene zwischengespeichert werden. Dies macht das Leben ein wenig schwieriger beim Schreiben von Anwendungscode (schwieriger beim Schreiben von LINQ), aber die Datenbank wird viel besser getroffen:

    1. Listenansichten - erzeugen SELECTbeim Laden keine Abfragen (alles wird zwischengespeichert) oder Abfragen, die so aussehen:

      SELECT allcolumns FROM BigTable WHERE filter1 IN (val1, val2) AND filter2 IN (val11, val12)

      Alle anderen erforderlichen Werte werden über Cache-Lookups (O (1)) abgerufen, sodass keine komplexen Abfragen generiert werden.

    2. Ansichten bearbeiten - erzeugt SELECTAnweisungen wie diese:

      SELECT allcolumns FROM BigTable WHERE PKId = value1

(alle Filter und Werte sind ints)

Alexei
quelle
Diese Posts sind möglicherweise relevant, da einige logische, physikalische und praktische Aspekte in Bezug auf die Verwendung von Spalten mit systemgenerierten Ersatzwerten behandelt werden.
MDCCL

Antworten:

19

Abgesehen von zusätzlichem Speicherplatz (und wiederum Speicherauslastung und E / A) kann das Hinzufügen einer IDENTITY-Spalte auch zu Tabellen, die keine IDENTITY-Spalte benötigen , nicht wirklich schaden (ein Beispiel für eine Tabelle, die keine IDENTITY-Spalte benötigt) ist eine einfache Junction-Tabelle (wie das Zuordnen eines Benutzers zu seinen Berechtigungen).

Ich bin dagegen, sie in einem Blogbeitrag aus dem Jahr 2010 blind jedem einzelnen Tisch hinzuzufügen :

Ersatzschlüssel haben jedoch gültige Anwendungsfälle. Achten Sie jedoch darauf, dass Sie nicht davon ausgehen, dass sie eindeutig sind (weshalb sie manchmal hinzugefügt werden - sie sollten nicht die einzige Möglichkeit sein, eine Zeile eindeutig zu identifizieren). Wenn Sie ein ORM-Framework verwenden müssen und für Ihr ORM-Framework einspaltige Ganzzahlschlüssel erforderlich sind, stellen Sie sicher, dass Sie eindeutige Einschränkungen / Indizes definieren, auch wenn es sich bei Ihrem tatsächlichen Schlüssel entweder nicht um eine Ganzzahl oder nicht um eine einzelne Spalte handelt auch für Ihre echten Schlüssel.

Aaron Bertrand
quelle
Danke für die schnelle Antwort. Ja, die Anwendung verwendet ein ORM (EF). Es sind keine einzelnen ganzzahligen Spaltenschlüssel erforderlich, aber ich habe diese Einschränkung eingeführt, um einige generische Operationen (in Bezug auf das Design) wesentlich zu vereinfachen. Außerdem speichern alle Anwendungs-Caches alles in Maps (Wörterbüchern), damit der Schlüssel schnell abgerufen werden kann. Der Schlüssel muss eindeutig sein. Da ich ints anstelle von guids ausgewählt habe, muss ich für jede Tabelle, in die ich einfügen möchte, IDENTITY verwenden. Für Tabellen mit festen Werten ist IDENTITY nicht erforderlich.
Alexei
Ich denke, es gibt einige Fälle, in denen die Eindeutigkeitsprüfung natürlicher Schlüssel vermieden werden muss. Als jemand, der mit GIS-Daten arbeitet, fällt einem sofort ein, dass der natürliche Schlüssel entweder nur die Geometrie selbst oder die Geometrie plus einen Fremdschlüssel ist. Das Nachschlagen anhand einer exakten Geometrie ist immer unpraktisch. Eine Einschränkung der Eindeutigkeit ist daher unwahrscheinlich und hat möglicherweise Leistungseinbußen. Dasselbe könnte zutreffen, wenn ein Teil des natürlichen Schlüssels eine lange Textspalte ist. Aber ich stimme zu: Wann immer es praktikabel ist, sollte eine eindeutige Einschränkung für den natürlichen Schlüssel angewendet werden.
jpmc26
13

Nach meiner Erfahrung ist der Haupt- und Hauptgrund für die Verwendung einer separaten ID für jede Tabelle der folgende:

In fast allen Fällen hat mein Kunde in der Konzeptionsphase einen BlutschwurXYZBLARGH_ID geleistet, wonach ein externes "natürliches" Feld für immer einzigartig bleibt und sich für eine bestimmte Entität niemals ändert und niemals wiederverwendet wird Die Primärschlüsseleigenschaften waren fehlerhaft. So funktioniert es einfach nicht.

Aus Sicht des Datenbankadministrators sind die Dinge, die eine Datenbank langsam oder aufgebläht machen, sicher nicht 4 Bytes (oder was auch immer) pro Zeile, sondern Dinge wie falsche oder fehlende Indizes, vergessene Tabellen- / Indexreorganisationen, falsche RAM- / Tabellenbereich-Optimierungsparameter , vernachlässigt die Verwendung von Bindevariablen und so weiter. Diese können den DB um den Faktor 10, 100, 10000 verlangsamen ... keine zusätzliche ID-Spalte.

Selbst wenn es einen technischen, messbaren Nachteil gäbe, zusätzliche 32 Bit pro Zeile zu haben, ist es keine Frage, ob Sie die ID wegoptimieren können, sondern ob die ID irgendwann unerlässlich sein wird, was mehr sein wird wahrscheinlich als nicht. Und ich werde nicht alle "weichen" Vorteile einer Softwareentwicklungshaltung abzählen (wie Ihr ORM-Beispiel oder die Tatsache, dass es für Softwareentwickler einfacher ist, wenn alle IDs von Entwurf den gleichen Datentyp haben und so weiter). .

Hinweis: Beachten Sie, dass Sie für n:mZuordnungstabellen keine separate ID benötigen, da für diese Tabellen die IDs der zugeordneten Entitäten einen Primärschlüssel bilden sollten. Ein Gegenbeispiel wäre eine seltsame n:mAssoziation, die aus irgendeinem bizarren Grund mehrere Assoziationen zwischen denselben beiden Entitäten zulässt. Diese benötigen dann ihre eigene ID-Spalte, um eine PK zu erstellen. Es gibt ORM-Bibliotheken, die jedoch nicht mit mehrspaltigen PKs umgehen können. Dies wäre ein Grund, umsichtig mit den Entwicklern umzugehen, wenn sie mit einer solchen Bibliothek arbeiten müssen.

AnoE
quelle
2
"seltsame n: m Assoziation, die mehrere Assoziationen zwischen denselben zwei Entitäten erlaubt", SEHR allgemein im wirklichen Leben. Beispielsweise besitzt eine Person ein Auto, und die Anforderungen ändern sich zu dem Zeitpunkt, an dem der Besitz begann und endete. (Eine Person kann ein Auto verkaufen und später zurückkaufen und Ihre Software zum Absturz bringen.)
Ian Ringrose
Ja, so ähnlich, @IanRingrose.
AnoE
6

Wenn Sie ausnahmslos jeder Tabelle eine bedeutungslose zusätzliche Spalte hinzufügen und nur diese Spalten als Fremdschlüssel referenzieren, wird die Datenbank fast zwangsläufig komplexer und schwieriger zu verwenden sein. Tatsächlich entfernen Sie Daten, die für Benutzer von Interesse sind, aus den Fremdschlüsselattributen und zwingen den Benutzer / die Anwendung, einen zusätzlichen Join durchzuführen, um dieselben Informationen abzurufen. Abfragen werden komplexer, die Arbeit des Optimierers wird schwieriger und die Leistung kann leiden.

Ihre Tabellen werden spärlicher mit "echten" Daten gefüllt, als dies sonst der Fall gewesen wäre. Die Datenbank wird daher schwieriger zu verstehen und zu überprüfen sein. Möglicherweise ist es auch schwierig oder unmöglich, bestimmte nützliche Einschränkungen durchzusetzen (wobei für Einschränkungen mehrere Attribute erforderlich sind, die sich nicht mehr in derselben Tabelle befinden).

Ich würde vorschlagen, dass Sie Ihre Schlüssel sorgfältiger auswählen und sie nur dann ganzzahlig machen, wenn Sie gute Gründe dafür haben. Bauen Sie Ihre Datenbankdesigns auf eine gute Analyse, Datenintegrität, Praktikabilität und überprüfbare Ergebnisse, anstatt sich auf dogmatische Regeln zu verlassen.

nvogel
quelle
1
Und dennoch haben viele Systeme synthetische ganzzahlige Primärschlüssel auf jeder Tabelle (zum Beispiel fast jede Ruby on Rails-App, die jemals geschrieben wurde), ohne an solchen Problemen zu leiden. Sie leiden auch nie unter dem Problem, Änderungen an Primärschlüsseln (die eigentlich nie vorkommen sollten) auf alle Fremdschlüsseltabellen übertragen zu müssen.
David Aldridge
2
Die Frage fragte nach möglichen Nachteilen, daher meine Antwort. Ich leugne nicht, dass Ersatzschlüssel sinnvoll sein können, wenn sie mit Bedacht verwendet werden. Ich habe jedoch Tabellen mit 3,4,5 (oder viel mehr) bedeutungslosen Fremdschlüsseln gesehen, für die daher mindestens 3,4,5 Joins erforderlich waren, um nützliche Ergebnisse zu erzielen. Ein pragmatischeres Design hätte möglicherweise überhaupt keine Verbindungen erfordern können.
nvogel
1
Ich bin nicht davon überzeugt, dass die Ausführung solcher Abfragen das Hauptproblem bei einem solchen Entwurf ist - es ist das Schreiben der Abfrage, gegen die sie häufig Einwände erheben.
David Aldridge
5

Nach meiner Erfahrung mit verschiedenen Datenbanken ist ein Integer-Primärschlüssel immer besser als die Anwendungen, für die überhaupt keine Schlüssel definiert sind. Oder die Schlüssel haben, die ein halbes Dutzend varchar-Spalten auf unangenehme Weise verbinden, die nicht logisch sind ... (Seufzer)

Ich habe Anwendungen gesehen, die von ganzzahligen PKs auf GUIDs umgestellt haben. Der Grund dafür war, dass in bestimmten Fällen Daten aus mehreren Quellendatenbanken zusammengeführt werden mussten. Die Entwickler haben alle Schlüssel auf GUIDs umgestellt , sodass die Zusammenführung ohne Angst vor Datenkollisionen erfolgen kann, auch bei Tabellen, die nicht Teil der Zusammenführung waren (nur für den Fall, dass diese Tabellen jemals Teil einer zukünftigen Zusammenführung wurden).

Ich würde sagen, eine Ganzzahl-PK wird Sie nicht beißen, es sei denn, Sie planen, Daten aus unterschiedlichen Quellen zusammenzuführen, oder Sie haben Daten, die über Ihre Ganzzahl-Größengrenzen hinausgehen - es macht Spaß und ist ein Spiel, bis Ihnen der Platz für Einfügungen ausgeht .

Ich werde jedoch sagen, dass es sinnvoll sein kann , Ihren Clustered-Index für eine andere Spalte als Ihre PK festzulegen, wenn die Tabelle auf diese Weise häufiger abgefragt wird. Dies ist jedoch ein Ausnahmefall, insbesondere wenn der Großteil der Aktualisierungen und Auswahlen auf den PK-Werten basiert.

Nocken
quelle
2
Klingt nach einer schrecklichen Rechtfertigung, um alle Schlüssel in Guids zu ändern. Ich arbeite derzeit mit einer Datenbank, die Guids für alle Ersatzschlüssel verwendet. Es macht keinen Spaß.
Andy
2
Nein, die Verwendung von GUIDs macht keinen Spaß. Ich mag sie nicht, aber ich respektiere ihren Wert in bestimmten Anwendungsfällen.
CaM
2

Zur Seite legen:

  • Die Religionskriege (Google Surrogate vs Natural Key)
  • Die separate Frage, welche Clustered-Indizes für Ihre Tabellen definiert werden sollen
  • Die Möglichkeit, alle Ihre Daten zwischenzuspeichern

Vorausgesetzt, Sie verwenden Bulk-Lösch- / Aktualisierungsfunktionen und verfügen über Indizes, um solche Vorgänge zu unterstützen. Ich glaube nicht, dass Sie aufgrund des von Ihnen verwendeten PK-Standards auf Probleme stoßen werden.
Es ist möglich, dass EF-Abfragen mit Joins usw. später nicht so effizient sind wie mit einem natürlichen schlüsselbasierten Repository, aber ich weiß nicht genug über diesen Bereich, um es mit Sicherheit so oder so zu sagen.

TH
quelle
4
Ich kann mir keinen Einzelfall vorstellen, in dem ein Join für einen natürlichen Schlüssel effizienter wäre als ein Join für eine ganze Zahl - nicht viele natürliche Schlüssel können kleiner als 4 Byte sein, und wenn ja, kann es nicht genug eindeutige Schlüssel geben Reihen, um den Unterschied Material zu machen.
Aaron Bertrand
Für kompetentes, optimierbares SQL stimme ich zu, bezog mich aber auf mögliche Einschränkungen von SQL-Generatoren. Meine einzige Erfahrung in diesem Bereich besteht darin, umfangreiche Ansichten zu erstellen, mit denen EF mit dem Löffel gefüttert werden kann - obwohl die .NET-Entwickler möglicherweise nicht genug über EF wussten oder dass es andere Gründe gab.
TH
@AaronBertrand Ich würde sagen, dass sie nur dann effizienter sind, wenn ein Join überhaupt nicht benötigt wird. Die einzigen Stellen, an denen ich die Verwendung von natürlichen Schlüsseln in Betracht ziehe, sind Standardcodelisten wie ISO4127-Währungscodes (die vom Menschen erkannt werden), und ich könnte GBP, EUR usw. als Fremdschlüssel für einen Primär- oder Alternativschlüssel im Währungscode verwenden Tabelle.
David Aldridge
@ David Natürlich sprach ich über Fälle, in denen Verknüpfungen notwendig sind. Es gibt viele Fälle, in denen ich nicht möchte, dass der natürliche Schlüssel in allen zugehörigen Tabellen verbreitet wird, weil sich natürliche Schlüssel ändern können, und das ist eine schmerzhafte Sache.
Aaron Bertrand
Hmmm, ich sehe, wie meine Antwort missverstanden werden könnte, natürliche Fremdschlüssel anstelle von Ersatz zu fördern. Klar, ich habe sie eigentlich nur erwähnt, weil a) ich Alexeis Frage gelesen habe: "Ist es ein Problem, dass wir keine natürlichen Schlüssel verwenden?", B) Alexeis Abschlussfrage begann mit "aus der Sicht eines DBAs" und ich Ich war der Meinung, dass ich irgendwie anerkennen sollte, dass es mehr als eine Perspektive gibt, und c) weil ich der Meinung wäre, dass die zu verwendenden ORM-Funktionen weitgehend die Wahl bestimmen (ob sie tatsächlich einen Unterschied machen können). Ich bin selbst fest im Ersatz-Fremdschlüssel-Lager.
TH
2

Sie haben ein paar Faktoren, die Ihnen helfen,

  1. Definition und Spezifikation

    Wenn etwas durch die Aufgabe oder die Gesetze der Physik als einzigartig definiert ist, verschwenden Sie Ihre Zeit mit einem Ersatzschlüssel.

  2. Einzigartigkeit.

    Für die persönliche Vernunft, Verknüpfungen und Datenbankfunktionen auf höherer Ebene benötigen Sie entweder (a) eine eindeutige Spalte, (b) eine eindeutige Reihe von Spalten

    Alle ausreichend normalisierten Schemata (1NF) bieten eine der folgenden Möglichkeiten. Wenn nicht, sollten Sie immer eine erstellen. Wenn Sie eine Liste von Personen haben, die sich am Sonntag freiwillig melden, und die den Nachnamen und den Vornamen enthält, möchten Sie wissen, wann Sie zwei Joe Bobs haben.

  3. Implementierung und Optimierung.

    Ein Int ist in der Regel eine kleine Datenform, die schnell zum Vergleich und zur Gleichheit dient. Vergleichen Sie dies mit einer Unicode-Zeichenfolge, deren Sortierung vom Gebietsschema (Standort und Sprache) abhängig sein kann. Das Speichern eines 4242 in einer ASCII / UTF8-Zeichenfolge umfasst 4 Byte. Speichern Sie es als Ganzzahl, es passt in 2 Bytes.

Wenn es also um Nachteile geht, gibt es ein paar Faktoren.

  1. Verwirrung und Mehrdeutigkeit.

    1. @ Aaron Bertrand Blog-Eintrag fasst dies gut zusammen. Es ist nicht selbstdokumentierend, eine OrderID nach Spezifikation und Aufgabe zu haben und dann eine " OrderID " durch die Datenbankimplementierung zu erzwingen . Manchmal müssen Sie dies klarstellen oder eine Konvention erstellen, aber dies kann zu Verwirrung führen.
  2. Platz.

    Ganzzahlen fügen der Zeile noch Platz hinzu. Und wenn Sie sie nicht verwenden, gibt es keinen Zweck.

  3. Clustering.

    Sie können Ihre Daten nur in eine Richtung bestellen. Wenn Sie einen Ersatzschlüssel auferlegen, der nicht benötigt wird, gruppieren Sie diesen oder den natürlichen Schlüssel?

Evan Carroll
quelle
Nette und kurze Vor- und Nachteile.
Alexei
@ Alexei danke, erwägen Sie, es als ausgewählt zu markieren, wenn es das erfüllt, was Sie suchen. Oder um Klarstellung bitten.
Evan Carroll