Warum würde sich ein Primärschlüsselwert ändern?

18

Ich habe kürzlich das Konzept von ROWGUID untersucht und bin auf diese Frage gestoßen . Diese Antwort gab einen Einblick, hat mich aber zu einem anderen Kaninchenbau geführt, mit der Erwähnung, den Primärschlüsselwert zu ändern.

Mein Verständnis war schon immer, dass ein Primärschlüssel unveränderlich sein sollte, und meine Suche seit dem Lesen dieser Antwort ergab nur Antworten, die die gleichen wie eine bewährte Vorgehensweise widerspiegeln.

Unter welchen Umständen muss ein Primärschlüsselwert geändert werden, nachdem der Datensatz erstellt wurde?

5 voll
quelle
7
Wenn ein Primärschlüssel gewählt wird, der nicht unveränderlich ist?
Ypercubeᵀᴹ
2
Nur eine Nebensache zu allen unten stehenden Antworten. Das Ändern eines Werts im Primärschlüssel ist keine große Sache, es sei denn, der Primärschlüssel ist zufällig auch der Clustered-Index. Es ist nur wirklich wichtig, ob sich die Werte des Clustered-Index ändern.
Kenneth Fisher
6
@KennethFisher oder wenn es von einem (oder mehreren) FKs in einer anderen oder derselben Tabelle referenziert wird und eine Änderung in viele (möglicherweise Millionen oder Milliarden) Zeilen kaskadiert werden muss.
ypercubeᵀᴹ
9
Fragen Sie Skype. Als ich mich vor einigen Jahren angemeldet habe, habe ich meinen Benutzernamen falsch eingegeben (ich habe einen Buchstaben hinter meinem Nachnamen gelassen). Ich habe viele Male versucht, es zu korrigieren, aber sie konnten es nicht ändern, weil es für den Primärschlüssel verwendet wurde und sie es nicht unterstützten, es zu ändern. In diesem Fall möchte der Kunde, dass der Primärschlüssel geändert wird, aber Skype hat dies nicht unterstützt. Sie könnten diese Änderung unterstützen, wenn sie möchten (oder sie könnten ein besseres Design schaffen), aber es gibt derzeit nichts, was dies zulässt. Mein Benutzername ist also immer noch falsch.
Aaron Bertrand
3
Alle realen Werte können sich ändern (aus einer Vielzahl von Gründen). Dies war eine der ursprünglichen Motivationen für Ersatz- / Syntheseschlüssel: künstliche Werte erzeugen zu können, auf die man sich verlassen konnte, um sich nie zu ändern.
RBarryYoung

Antworten:

24

Wenn Sie den Namen einer Person als Primärschlüssel verwenden und deren Name geändert wird, müssen Sie den Primärschlüssel ändern. Dies wird ON UPDATE CASCADEverwendet, da es die Änderung im Wesentlichen auf alle verknüpften Tabellen kaskadiert , die Fremdschlüsselbeziehungen zum Primärschlüssel haben.

Beispielsweise:

USE tempdb;
GO

CREATE TABLE dbo.People
(
    PersonKey VARCHAR(200) NOT NULL
        CONSTRAINT PK_People
        PRIMARY KEY CLUSTERED
    , BirthDate DATE NULL
) ON [PRIMARY];

CREATE TABLE dbo.PeopleAKA
(
    PersonAKAKey VARCHAR(200) NOT NULL
        CONSTRAINT PK_PeopleAKA
        PRIMARY KEY CLUSTERED
    , PersonKey VARCHAR(200) NOT NULL
        CONSTRAINT FK_PeopleAKA_People
        FOREIGN KEY REFERENCES dbo.People(PersonKey)
        ON UPDATE CASCADE
) ON [PRIMARY];

INSERT INTO dbo.People(PersonKey, BirthDate)
VALUES ('Joe Black', '1776-01-01');

INSERT INTO dbo.PeopleAKA(PersonAKAKey, PersonKey)
VALUES ('Death', 'Joe Black');

A SELECTgegen beide Tische:

SELECT *
FROM dbo.People p
    INNER JOIN dbo.PeopleAKA pa ON p.PersonKey = pa.PersonKey;

Kehrt zurück:

Bildbeschreibung hier eingeben

Wenn wir die PersonKeySpalte aktualisieren und Folgendes erneut ausführen SELECT:

UPDATE dbo.People
SET PersonKey = 'Mr Joe Black'
WHERE PersonKey = 'Joe Black';

SELECT *
FROM dbo.People p
    INNER JOIN dbo.PeopleAKA pa ON p.PersonKey = pa.PersonKey;

wir sehen:

Bildbeschreibung hier eingeben

Wenn UPDATEwir den Plan für die obige Anweisung betrachten, sehen wir deutlich, dass beide Tabellen durch eine einzelne Aktualisierungsanweisung aufgrund des Fremdschlüssels aktualisiert werden, der wie folgt definiert ist ON UPDATE CASCADE:

Bildbeschreibung hier eingeben Klicken Sie auf das Bild, um es deutlicher zu sehen

Zuletzt bereinigen wir unsere temporären Tabellen:

DROP TABLE dbo.PeopleAKA;
DROP TABLE dbo.People;

Die bevorzugte 1 Möglichkeit, dies mit Ersatzschlüsseln zu tun, wäre:

USE tempdb;
GO

CREATE TABLE dbo.People
(
    PersonID INT NOT NULL IDENTITY(1,1)
        CONSTRAINT PK_People
        PRIMARY KEY CLUSTERED
    , PersonName VARCHAR(200) NOT NULL
    , BirthDate DATE NULL
) ON [PRIMARY];

CREATE TABLE dbo.PeopleAKA
(
    PersonAKAID INT NOT NULL IDENTITY(1,1)
        CONSTRAINT PK_PeopleAKA
        PRIMARY KEY CLUSTERED
    , PersonAKAName VARCHAR(200) NOT NULL
    , PersonID INT NOT NULL
        CONSTRAINT FK_PeopleAKA_People
        FOREIGN KEY REFERENCES dbo.People(PersonID)
        ON UPDATE CASCADE
) ON [PRIMARY];

INSERT INTO dbo.People(PersonName, BirthDate)
VALUES ('Joe Black', '1776-01-01');

INSERT INTO dbo.PeopleAKA(PersonID, PersonAKAName)
VALUES (1, 'Death');

SELECT *
FROM dbo.People p
    INNER JOIN dbo.PeopleAKA pa ON p.PersonID = pa.PersonID;

UPDATE dbo.People
SET PersonName = 'Mr Joe Black'
WHERE PersonID = 1;

Der Vollständigkeit halber ist der Plan für die Aktualisierungsanweisung sehr einfach und zeigt einen Vorteil gegenüber Ersatzschlüsseln: Im Gegensatz zu jeder Zeile, die den Schlüssel in einem Natural-Key-Szenario enthält , muss nur eine einzige Zeile aktualisiert werden:

Bildbeschreibung hier eingeben

SELECT *
FROM dbo.People p
    INNER JOIN dbo.PeopleAKA pa ON p.PersonID = pa.PersonID;

DROP TABLE dbo.PeopleAKA;
DROP TABLE dbo.People;

Die Ausgabe der beiden SELECTobigen Anweisungen lautet:

Bildbeschreibung hier eingeben

Im Wesentlichen ist das Ergebnis in etwa gleich. Ein wesentlicher Unterschied besteht darin, dass der breite natürliche Schlüssel nicht in jeder Tabelle wiederholt wird, in der der Fremdschlüssel vorkommt. In meinem Beispiel verwende ich eine VARCHAR(200)Spalte, um den Namen der Person zu speichern, was die Verwendung eines VARCHAR(200) überall erforderlich macht . Wenn viele Zeilen und Tabellen den Fremdschlüssel enthalten, wird viel Speicher verschwendet. Hinweis: Ich spreche nicht davon, dass Speicherplatz verschwendet wird, da die meisten Leute sagen, dass Speicherplatz so billig ist, dass er im Wesentlichen frei ist. Speicher ist jedoch teuer und verdient es, geschätzt zu werden. Wenn Sie eine 4-Byte-Ganzzahl für den Schlüssel verwenden, wird viel Speicherplatz gespart, wenn Sie die durchschnittliche Namenslänge von etwa 15 Zeichen berücksichtigen.

Tangential zu der Frage, wie und warum sich Schlüssel ändern können, ist die Frage, warum natürliche Schlüssel anstelle von Ersatzschlüsseln gewählt werden. Dies ist eine interessante und vielleicht wichtigere Frage, insbesondere, wenn Leistung ein Entwurfsziel ist. Siehe meine Frage dazu hier .


1 - http://weblogs.sqlteam.com/mladenp/archive/2009/10/06/Warum-Ich-präferiere-surrogate-keys-instead-of-natural-keys-in.aspx

Max Vernon
quelle
3
Um CASCADE (das in bestimmten Szenarien Probleme verursacht) zu vermeiden, können Sie die FK-Spalten auch auf null setzen. Wenn Sie also die PK ändern müssen, können Sie die zugehörigen Zeilen auf NULL aktualisieren (in Teilen, wenn es viele gibt, oder nach Tabelle) Wenn viele Tabellen vorhanden sind (oder beides), ändern Sie den PK-Wert und anschließend die FKs erneut.
Aaron Bertrand
8

Während Sie einen natürlichen und / oder veränderlichen Schlüssel als PK verwenden können, führt dies nach meiner Erfahrung zu Problemen, die häufig durch die Verwendung eines PK verhindert werden können, der diese Bedingungen erfüllt:

 Guaranteed Unique, Always Exists, Immutable, and Concise.

Beispielsweise versuchen viele Unternehmen in den USA, Sozialversicherungsnummern als persönliche ID-Nummern (und PKs) in ihren Systemen zu verwenden. Dann treten folgende Probleme auf: Dateneingabefehler, die zu mehreren zu reparierenden Datensätzen führen, Personen ohne SSN, Personen, deren SSN von der Regierung geändert wurde, Personen mit doppelten SSNs.

Ich habe jedes einzelne dieser Szenarien gesehen. Ich habe auch Firmen gesehen, die nicht wollten, dass ihre Kunden "nur eine Nummer" sind, was bedeutete, dass ihre PK "First + Middle + Last + DOB + Zip" oder ein ähnlicher Unsinn war. Sie haben zwar genug Felder hinzugefügt, um fast die Eindeutigkeit zu gewährleisten, aber ihre Abfragen waren entsetzlich, und die Aktualisierung eines dieser Felder bedeutete, Probleme mit der Datenkonsistenz zu beseitigen.

Nach meiner Erfahrung ist eine von der Datenbank selbst generierte PK fast immer eine bessere Lösung.

Ich empfehle diesen Artikel für zusätzliche Hinweise: http://www.agiledata.org/essays/keys.html

Byron Jones
quelle
6
Ein guter Ratschlag aus dem Scott Ambler-Artikel, auf den in Ihrer Antwort verwiesen wird: "Einige Leute werden Ihnen sagen, dass Sie immer natürliche Schlüssel verwenden sollten, und andere werden Ihnen sagen, dass Sie immer Ersatzschlüssel verwenden sollten. Diese Leute erweisen sich normalerweise immer als falsch Sie teilen kaum mehr als die Vorurteile ihrer "Datenreligion" mit Ihnen. Die Realität ist, dass natürliche und Ersatzschlüssel ihre Vor- und Nachteile haben und dass keine Strategie für alle Situationen perfekt ist. "
nvogel
7

Der Primärschlüssel kann geändert werden, wenn eine Synchronisierung erforderlich ist. Dies kann der Fall sein, wenn Sie einen nicht verbundenen Client haben und die Daten in bestimmten Intervallen mit dem Server synchronisiert werden.

Vor ein paar Jahren habe ich an einem System gearbeitet, in dem alle Ereignisdaten auf dem lokalen Computer negative Zeilen-IDs hatten, z. B. -1, -2 usw. Bei der Synchronisierung der Daten mit dem Server wurde die Zeilen-ID auf dem Server auf den Server angewendet Klient. Angenommen, die nächste Zeilen-ID auf dem Server war 58. Dann würde -1 zu 58, -2 zu 59 und so weiter. Diese Zeilen-ID-Änderung würde auf alle untergeordneten FK-Datensätze auf dem lokalen Computer kaskadiert. Der Mechanismus wurde auch verwendet, um zu bestimmen, welche Datensätze zuvor synchronisiert wurden.

Ich sage nicht, dass dies ein gutes Design war, aber es ist ein Beispiel dafür, wie sich der Primärschlüssel im Laufe der Zeit ändert.

Jon Raynor
quelle
5

Jedes Design, bei dem das PRIMARY KEYregelmäßig geändert wird, ist ein Rezept für eine Katastrophe. Der einzige gute Grund für eine Änderung wäre der Zusammenschluss von zwei zuvor getrennten Datenbanken.

Wie von @MaxVernon hervorgehoben, können gelegentliche Änderungen auftreten - dann verwenden ON UPDATE CASCADE, obwohl die meisten Systeme heutzutage eine ID als Ersatz verwenden PRIMARY KEY.

Puristen wie Joe Celko und Fabian Pascal (eine Seite, der man unbedingt folgen sollte) sind mit der Verwendung von Ersatzschlüsseln nicht einverstanden, aber ich denke, dass sie diesen Kampf verloren haben.

Vérace
quelle
3

Stabilität ist eine wünschenswerte Eigenschaft für einen Schlüssel, aber es ist eine relative Sache und keine absolute Regel. In der Praxis ist es oft nützlich, die Werte von Schlüsseln zu ändern. In relationaler Hinsicht sind Daten nur über ihre (Super-) Schlüssel identifizierbar. Wenn es nur einen Schlüssel in einer gegebenen Tabelle gibt, dann ist die Unterscheidung zwischen A) Ändern eines Schlüsselwerts oder B) Ersetzen der Reihe von Zeilen in einer Tabelle durch eine ähnliche oder andere Reihe von Zeilen, die andere Schlüsselwerte enthalten, im wesentlichen eher eine Frage der Semantik als der Logik.

Ein interessanteres Beispiel ist der Fall einer Tabelle mit mehreren Schlüsseln, bei der sich die Werte eines oder mehrerer dieser Schlüssel möglicherweise im Verhältnis zu anderen Schlüsselwerten ändern müssen. Nehmen Sie das Beispiel einer Employee-Tabelle mit zwei Schlüsseln: LoginName und Badge Number. Hier ist eine Beispielzeile aus dieser Tabelle:

+---------+--------+
|LoginName|BadgeNum|
+---------+--------+
|ZoeS     |47832   |
+---------+--------+

Wenn ZoeS ihren Ausweis verliert, erhält sie möglicherweise einen neuen Ausweis und eine neue Ausweisnummer:

+---------+--------+
|LoginName|BadgeNum|
+---------+--------+
|ZoeS     |50282   |
+---------+--------+

Später könnte sie beschließen, ihren Anmeldenamen zu ändern:

+---------+--------+
|LoginName|BadgeNum|
+---------+--------+
|ZSmith   |50282   |
+---------+--------+

Beide Schlüsselwerte veränderten sich - im Verhältnis zueinander. Es ist zu beachten, dass es nicht unbedingt einen Unterschied macht, welches als "primär" eingestuft wird.

In der Praxis ist "Unveränderlichkeit", dh absolut nie eine Änderung eines Wertes, unerreichbar oder zumindest unmöglich zu überprüfen. In dem Maße, in dem Änderungen überhaupt einen Unterschied bewirken, ist es wahrscheinlich am sichersten anzunehmen, dass sich ein Schlüssel (oder ein Attribut) ändern muss.

nvogel
quelle
Ich habe Ihren Kommentar aufgrund der folgenden Aussage zurückgestuft: "In der Praxis ist" Unveränderlichkeit ", dh absolut nie eine Änderung eines Wertes, unerreichbar oder zumindest unmöglich zu überprüfen." Unveränderlichkeit IST möglich und ist einer der wichtigsten Gründe für die Verwendung von Ersatzschlüsseln.
Byron Jones
3
Woher wissen Sie, dass jemand nächste Woche oder in 10 Jahren keinen Schlüsselwert mehr ändert? Sie können davon ausgehen, dass dies nicht der Fall ist, aber Sie können dies nicht realistisch verhindern (wenn Sie die alleinige Verantwortung tragen, können Sie Barrieren errichten, um alle anderen auf Dauer fernzuhalten, aber das scheint ein Randfall zu sein). Was wirklich zählt, ist, dass Änderungen sehr selten sind und nicht, dass sie niemals eintreten werden.
nvogel
3

Interessanterweise bietet die verknüpfte Frage zu ROWGUID einen eigenen Anwendungsfall: Wenn in Datenbanken, die synchronisiert werden müssen, widersprüchliche Primärschlüssel vorliegen. Wenn Sie zwei Datenbanken haben, die abgeglichen werden müssen, und diese Sequenzen für Primärschlüssel verwenden, möchten Sie, dass einer der Schlüssel geändert wird, damit er eindeutig bleibt.

In einer idealen Welt würde dies niemals passieren. Sie würden zunächst GUIDs für die Primärschlüssel verwenden. Realistisch gesehen ist es jedoch möglich, dass Sie zu Beginn des Entwurfs noch nicht einmal über eine verteilte Datenbank verfügen. Die Konvertierung in GUIDs war möglicherweise eine Maßnahme, die im Folgenden als vorrangig eingestuft wurde, da sie eine höhere Auswirkung hatte als die Implementierung des Schlüsselupdates. Dies kann vorkommen, wenn Sie über eine große Codebasis verfügen, die von Ganzzahlschlüsseln abhängt und für die Konvertierung in die GUID eine umfangreiche Überarbeitung erforderlich ist. Es gibt auch die Tatsache, dass spärliche GUIDs (GUIDs, die nicht sehr nah beieinander liegen, was passiert, wenn Sie sie zufällig generieren, wie Sie sollten) Probleme für bestimmte Arten von Indizes verursachen können, was bedeutet, dass Sie die Verwendung vermeiden möchten sie als Primärschlüssel (erwähnt von Byron Jones ).

jpmc26
quelle
0

Ein mögliches Szenario ist, dass Sie über Partner mit einer eindeutigen ID verfügen und wissen, dass sie nicht über Partner hinweg dupliziert werden, da sie einen eindeutigen Startcharakter haben. Die Partner laden Daten in eine Mastertabelle. Dort werden Datensätze verarbeitet und anschließend eine Master-ID vergeben. Benutzer benötigen Zugriff auf die Datensätze, sobald sie geladen sind, auch wenn sie noch nicht verarbeitet wurden. Sie möchten, dass die Master-ID auf der verarbeiteten Bestellung basiert und nicht immer in der Reihenfolge verarbeitet wird, in der die Datensätze geladen wurden. Ich weiß, ein bisschen erfunden.

Paparazzo
quelle
-1

Stellen Sie sich eine Situation vor, in der jemand die NIN (National Insurance Number) als Primärschlüssel gewählt hat und auf irgendeine Weise ein Bediener eine Zeile mit der falschen NIN einfügt. Nach dem Einfügen des Werts gibt es zwei Möglichkeiten, um den Fehler zu beheben:

  1. Löschen Sie den fehlerhaften Datensatz und fügen Sie einen neuen ein
  2. Aktualisieren Sie den Wert auf den richtigen Wert und verwenden Sie On Update Cascade, wenn für diese Spalte eine referenzielle Integritätsbedingung besteht
Behrouz Sameny
quelle