Ich entwickle eine SQL Server 2012-Datenbank und habe Zweifel an nvarchar-Spalten als Primärschlüssel.
Ich habe diese Tabelle:
CREATE TABLE [dbo].[CODES]
(
[ID_CODE] [bigint] IDENTITY(1,1) NOT NULL,
[CODE_LEVEL] [tinyint] NOT NULL,
[CODE] [nvarchar](20) NOT NULL,
[FLAG] [tinyint] NOT NULL,
[IS_TRANSMITTED] [bit] NOT NULL DEFAULT 0,
CONSTRAINT [PK_CODES] PRIMARY KEY CLUSTERED
(
[CODE_LEVEL] ASC,
[CODE] ASC
)
)
Aber jetzt möchte ich die [CODE]
Spalte als Primärschlüssel verwenden und die [ID_CODE]
Spalte entfernen .
Gibt es ein Problem oder eine Strafe, wenn ich eine NVARCHAR
Spalte als habe PRIMARY KEY
?
[CODE]
Der Spaltenwert muss eindeutig sein, daher habe ich gedacht, dass ich eine UNIQUE
Einschränkung für diese Spalte festlegen kann .
Muss ich [CODE]
als Primärschlüssel verwenden oder ist es besser, wenn ich eine UNIQUE
Einschränkung für die [CODE]
Spalte festlege ?
sql-server
primary-key
unique-constraint
VansFannel
quelle
quelle
CODE
Spalte eindeutig sein sollte, aber keinen Primärschlüssel. Ich vermute, dass es Informationen enthält. Wenn diese Informationen in irgendeiner WeiseCODE
geändert werden können, sollten Sie sich ändern oder veraltet sein. Das würde Ihren Primärschlüssel flüchtig machen, und ich kann nicht sehen, dass das gut endet. Lassen Sie Ihre PK am besten nur ein Schlüssel sein, und Ihr CODE kann tun, was er will. Nur eine Meinung.Antworten:
Ja, es gibt absolut negative Konsequenzen für die Verwendung einer Zeichenfolge anstelle eines numerischen Typs für einen Primärschlüssel, und dies umso mehr, wenn diese PK geclustert ist (was in Ihrem Fall tatsächlich der Fall ist). Der Grad, in dem Sie die Auswirkung (en) der Verwendung eines Zeichenfolgenfelds sehen, hängt jedoch davon ab, a) wie viele Zeilen sich in dieser Tabelle befinden und b) wie viele Zeilen in anderen Tabellen für diese PK mit einem Fremdschlüssel versehen sind. Wenn Sie nur 10.000 Zeilen in dieser Tabelle und 100.000 Zeilen in einigen anderen Tabellen haben, die über dieses Feld an diese Tabelle weitergeleitet werden, ist dies möglicherweise nicht so auffällig. Aber diese Effekte werden mit zunehmender Anzahl der Zeilen sicherlich deutlicher.
Sie müssen berücksichtigen, dass die Felder in einem Clustered-Index auf Nicht-Clustered-Indizes übertragen werden. Sie betrachten also nicht nur bis zu 40 Bytes pro Zeile, sondern (40 * some_number) Bytes. Und in allen FK-Tabellen haben Sie dieselben 40 Bytes in der Zeile. In den meisten Fällen gibt es einen nicht gruppierten Index für dieses Feld, wie er in JOINs verwendet wird. In allen Tabellen, in denen FK verwendet wird, wird er jetzt wirklich verdoppelt dieses. Wenn man denkt, dass 40 Bytes * 1 Million Zeilen * 10 Kopien davon kein Grund zur Sorge sind, lesen Sie bitte meinen Artikel Disk Is Cheap! ORLY? Darin werden alle (oder zumindest die meisten) Bereiche aufgeführt, die von dieser Entscheidung betroffen sind.
Die andere zu berücksichtigende Sache ist, dass das Filtern und Sortieren nach Zeichenfolgen, insbesondere wenn keine binäre Kollatierung verwendet wird (ich gehe davon aus, dass Sie den Datenbankstandard verwenden, bei dem die Groß- und Kleinschreibung normalerweise nicht berücksichtigt wird), weitaus weniger effizient ist (dh länger dauert) als bei Verwendung von
INT
/BIGINT
. Dies wirkt sich auf alle Abfragen aus, die in diesem Feld gefiltert / verknüpft / sortiert werden.Daher
CHAR(5)
wäre die Verwendung von so etwas für eine Clustered PK wahrscheinlich in Ordnung, aber meistens, wenn es auch mitCOLLATE Latin1_General_100_BIN2
(oder so ähnlich) definiert wurde.Und kann sich der Wert von
[CODE]
jemals ändern? Wenn ja, dann ist das noch mehr Grund, es nicht als PK zu verwenden (selbst wenn Sie die FKs auf setzenON UPDATE CASCADE
). Wenn es sich nicht ändern kann oder wird, ist das in Ordnung, aber es gibt bereits mehr als genug Gründe, es nicht als Clustered PK zu verwenden.Natürlich könnte die Frage falsch formuliert sein, da es den Anschein hat, dass Sie dieses Feld derzeit bereits in Ihrer PK haben.
Unabhängig davon ist es bei weitem die beste Option,
[ID_CODE]
als Clustered PK zu verwenden, dieses Feld in verwandten Tabellen als FK zu verwenden und[CODE]
als zu behaltenUNIQUE INDEX
(was bedeutet, dass es sich um einen "alternativen Schlüssel" handelt).Update
Ein bisschen mehr Infos basierend auf dieser Frage in einem Kommentar zu dieser Antwort:
Dies alles hängt von sehr vielen Faktoren ab, von denen ich einige bereits erwähnt habe, aber noch einmal wiederholen werde:
Ein Primärschlüssel gibt an, wie die einzelne Zeile identifiziert wird, unabhängig davon, ob sie von einem Fremdschlüssel referenziert wird oder nicht. Wie Ihr System die Zeile intern identifiziert, hängt damit zusammen, aber nicht unbedingt mit der Art und Weise, wie Ihre Benutzer sich selbst / diese Zeile identifizieren. Jede NOT NULL-Spalte mit eindeutigen Daten könnte funktionieren, es sind jedoch praktische Aspekte zu berücksichtigen, insbesondere wenn die PK tatsächlich von FKs referenziert wird. Zum Beispiel sind GUIDs einzigartig und einige Leute verwenden sie aus verschiedenen Gründen sehr gerne, aber sie sind ziemlich schlecht für Clustered-Indizes (
NEWSEQUENTIALID
ist besser, aber nicht perfekt). Auf der anderen Seite sind GUIDs als alternative Schlüssel in Ordnung und werden von der App zum Nachschlagen der Zeile verwendet. Die JOINs werden jedoch weiterhin mit einer INT-PK (oder einer ähnlichen PK) ausgeführt.Bisher haben Sie uns nicht gesagt, wie das
[CODE]
Feld aus allen Blickwinkeln in das System passt, außer jetzt zu erwähnen, dass Sie auf diese Weise Zeilen nachschlagen, aber ist das für alle Abfragen oder nur für einige? Daher:Zum
[CODE]
Wert:Zu dieser Tabelle:
[CODE]
oder[ID_CODE]
) in anderen Tabellen verwendet, auch wenn sie nicht explizit mit Fremdschlüssel versehen sind?[CODE]
das einzige Feld zum Abrufen einzelner Zeilen verwendet wird, welchen Zweck erfüllt das[ID_CODE]
Feld dann? Wenn es nicht verwendet wird, warum sollte es überhaupt verwendet werden (was von der Antwort auf "Kann sich das[CODE]
Feld jemals ändern?" Hängt )?Diese Entscheidung kann nicht nur über die Frage "NVARCHAR ja oder nein?" Ich werde noch einmal sagen, dass ich es im Allgemeinen nicht für eine gute Idee halte, aber es gibt sicherlich Zeiten, in denen es in Ordnung ist. Bei so wenigen Feldern in dieser Tabelle ist es unwahrscheinlich, dass es mehr oder zumindest nicht viele Indizes gibt. In beiden
[CODE]
Fällen kann es also in Ordnung sein, den Clustered-Index zu verwenden. Und wenn keine anderen Tabellen auf diese Tabelle verweisen, ist es möglicherweise auch in Ordnung, sie zur PK zu machen. Wenn jedoch andere Tabellen auf diese Tabelle verweisen, würde ich mich für das[ID_CODE]
Feld als PK entscheiden, selbst wenn es nicht gruppiert ist.quelle
[ID_CODE]
asPRIMARY KEY
die beste Option, wenn ich[CODE]
die Tabelle zum Nachschlagen der Tabelle mit einer Spalte verwende?Sie müssen die Konzepte trennen:
Primärschlüssel ist ein Entwurfskonzept , eine logische Eigenschaft der Einträge in der Tabelle. Es sollte während der Lebensdauer des Tabelleneintrags unveränderlich sein und der Schlüssel sein, der in der Anwendung zum Verweisen auf den Eintrag verwendet wird.
Clustered Index ist ein Speicherkonzept , eine physikalische Eigenschaft. Es sollte der häufigste Zugriffspfad für Abfragen sein, in den meisten Fällen als Deckungsindex dienen und so viele Bereichsabfragen wie möglich erfüllen.
Ist nicht erforderlich, damit der Primärschlüssel der Clustered-Index ist. Sie können
ID_CODE
als PK und(CODE_LEVEL, CODE)
als Clustered Key haben. Oder umgekehrt.Ein größerer Clustered Key hat einige negative Auswirkungen, da der breitere Key eine geringere Dichte auf den Indexseiten und eine größere Größe aller nicht Clustered Indizes bedeutet. Zu diesem Thema wurden bereits Tonnen Tinte verschüttet, z. Beginnen Sie mit Weitere Überlegungen zum Clustering-Schlüssel - die Debatte über den Clustered-Index wird fortgesetzt! .
Der Kern der Sache ist jedoch, dass die Wahl des Clustered-Index-Schlüssels in erster Linie ein Kompromiss ist. Einerseits haben Sie Anforderungen an die Speichergröße mit allgemeinen Auswirkungen auf die Leistung (größerer Schlüssel -> größere Größe -> mehr E / A und E / A-Bandbreite ist wahrscheinlich die knappste Ressource, die Sie haben). Andererseits kann die Auswahl des falschen Clusterschlüssels im Namen der Platzersparnis Auswirkungen auf die Abfrageleistung haben, die häufig schlimmer sind als die Probleme, die sich aus einem breiten Schlüssel ergeben.
Die Wahl des Primärschlüssels sollte nicht einmal ein Problem sein: Ihr Datenmodell, Ihre App-Logik, sollte den Primärschlüssel bestimmen.
Davon abgesehen
NVARCHAR(20)
ist mein 2c: nicht breit. Ist eine absolut akzeptable Clusterschlüsselgröße, selbst für eine große Tabelle.quelle
[ID_CODE]
asPRIMARY KEY
die beste Option, wenn ich[CODE]
Spalte (und vielleicht[CODE_LEVEL]
) verwende, um die Tabelle nachzuschlagen?[CODE]
Spalte als Primärschlüssel verwenden.Ich würde niemals zulassen, dass jemand
nvarchar(20)
eine PK in meiner Datenbank erstellt. Sie verschwenden Speicherplatz und Cache-Speicher. Jeder Index in dieser Tabelle und alle dazugehörigen FKs replizieren diesen breiten Wert. Vielleicht ein Zeichen (20), wenn sie es rechtfertigen können. In welcher Art von Daten möchten Sie speichernCODE
? Müssen Sie wirklich nvarchar-Zeichen speichern? Ich neige dazu, PKs "interne" Werte zu machen, die von den Benutzern nicht gesehen werden, und ich versuche, Werte, die angezeigt werden, getrennt zu halten. Angezeigte Werte müssen manchmal geändert werden, was bei PKs + FKs sehr problematisch wird.Ist Ihnen auch klar, dass eine 'Bigint-Identität (1,1)' bis zu 9.223.372.036.854.775.807 erhöhen kann?
Wenn Sie diese Datenbank nicht für Google
int identity (1,1)
erstellen, reicht ein Normalwert mit einem Limit von über 2 Milliarden nicht aus?quelle
[ID_CODE]
asPRIMARY KEY
die beste Option, wenn ich[CODE]
die Tabelle zum Nachschlagen der Tabelle mit einer Spalte verwende? Vielen Dank.Es sollte keine inhärente / spürbare Strafe geben, außer dass Sie das Risiko eingehen, breite Tasten zu verwenden, wenn Sie nvarchar / varchar verwenden, wenn Sie dies nicht wissen. Vor allem, wenn Sie sie in zusammengesetzten Schlüsseln kombinieren.
Aber in Ihrem Beispiel einer (20) Länge sollte es Ihnen gut gehen, und ich würde mir darüber keine großen Sorgen machen. Denn wenn Sie mit CODE hauptsächlich Ihre Daten abfragen, klingt ein Clustered-Index sehr sinnvoll.
Sie sollten jedoch überlegen, ob Sie es tatsächlich als Primärschlüssel oder nur als eindeutigen (gruppierten) Index möchten. Es gibt einen (kleinen) Unterschied zwischen dem Clustered-Index und dem Primärschlüssel (im Grunde genommen identifiziert der Primärschlüssel Ihre Daten, aber der Index gibt an, wie Sie Daten abfragen). Wenn Sie möchten, können Sie Ihren ID_Code also genauso einfach wie einen Primärschlüssel erstellen und Erstellen Sie einen eindeutigen Clustered-Index über CODE. (Hinweis: SQL Server verwandelt Ihren Primärschlüssel automatisch in einen Clustered-Index, es sei denn, Sie haben den Clustered-Index manuell erstellt.)
Überlegen Sie auch, ob Sie ID_Code tatsächlich benötigen, jetzt haben Sie einen eindeutigen CODE.
quelle
NVARCHAR(20)
es eine Größe von maximal 40 Byte, und da es sich um eine Spalte mit variabler Länge handelt , ist es nicht wirklich die beste Wahl für einen Clustered-Index.ID_CODE
ein zu seinBIGINT IDENTITY
wäre hier die viel bessere Wahl!