Perché un valore di chiave primaria cambierebbe?


18

Di recente ho studiato il concetto di ROWGUID e mi sono imbattuto in questa domanda. Questa risposta mi ha dato un'idea, ma mi ha portato in una tana di coniglio diversa con la menzione di cambiare il valore della chiave primaria.

La mia comprensione è sempre stata che una chiave primaria dovrebbe essere immutabile e la mia ricerca da quando ho letto questa risposta ha fornito solo risposte che riflettono lo stesso di una buona pratica.

In quali circostanze un valore di chiave primaria dovrebbe essere modificato dopo la creazione del record?


7
Quando viene scelta una chiave primaria che non è immutabile?
ypercubeᵀᴹ

2
Finora solo una piccola chiacchierata a tutte le risposte sottostanti. La modifica di un valore nella chiave primaria non è un grosso problema a meno che la chiave primaria non sia anche l'indice cluster. Importa davvero solo se i valori dell'indice cluster cambiano.
Kenneth Fisher,

6
@KennethFisher o se fa riferimento a uno (o molti) FK in un'altra o nella stessa tabella e una modifica deve essere sovrapposta a molte (forse milioni o miliardi) di righe.
ypercubeᵀᴹ

9
Chiedi a Skype. Quando mi sono registrato diversi anni fa, ho digitato il mio nome utente in modo errato (ho lasciato una lettera fuori dal mio cognome). Ho provato molte volte a correggerlo, ma non sono riusciti a cambiarlo perché è stato utilizzato per la chiave primaria e non hanno supportato la modifica. Questa è un'istanza in cui il cliente desidera che venga cambiata la chiave primaria, ma Skype non l'ha supportata. Essi potrebbero sostenere che il cambiamento se volevano (o potrebbero creare un design migliore), ma non c'è attualmente nulla in atto per permetterlo. Quindi il mio nome utente è ancora errato.
Aaron Bertrand

3
Tutti i valori del mondo reale possono cambiare (per una varietà di cause). Questa era una delle motivazioni originali per le chiavi surrogate / sintetiche: essere in grado di generare valori artificiali su cui fare affidamento per non cambiare mai.
RBarryYoung,

Risposte:


24

Se stavi usando il nome di una persona come chiave primaria e il suo nome fosse cambiato, dovrai cambiare la chiave primaria. Questo è ciò per cui ON UPDATE CASCADEviene utilizzato poiché essenzialmente riduce a cascata la modifica a tutte le tabelle correlate che hanno relazioni chiave esterna con la chiave primaria.

Per esempio:

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 SELECTcontro entrambi i tavoli:

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

Ritorna:

inserisci qui la descrizione dell'immagine

Se aggiorniamo la PersonKeycolonna ed eseguiamo nuovamente 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;

vediamo:

inserisci qui la descrizione dell'immagine

Guardando il piano per l' UPDATEistruzione precedente , vediamo chiaramente che entrambe le tabelle sono aggiornate da una singola istruzione di aggiornamento in virtù della chiave esterna definita come ON UPDATE CASCADE:

inserisci qui la descrizione dell'immagine fai clic sull'immagine qui sopra per vederla in maggiore chiarezza

Infine, ripuliremo le nostre tabelle temporanee:

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

Il modo 1 preferito per farlo usando le chiavi surrogate sarebbe:

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;

Per completezza, il piano per l'istruzione update è molto semplice e mostra un vantaggio nel surrogare le chiavi, vale a dire che è necessario aggiornare solo una singola riga rispetto a ogni riga contenente la chiave in uno scenario a chiave naturale:

inserisci qui la descrizione dell'immagine

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

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

L'output delle due SELECTdichiarazioni precedenti sono:

inserisci qui la descrizione dell'immagine

In sostanza, il risultato è approssimativamente lo stesso. Una grande differenza è che l'ampia chiave naturale non viene ripetuta in ogni tabella in cui si verifica la chiave esterna. Nel mio esempio, sto usando una VARCHAR(200)colonna per contenere il nome della persona, che richiede l'uso di VARCHAR(200) ovunque . Se ci sono molte righe e molte tabelle contenenti la chiave esterna, ciò aggiungerà molta memoria sprecata. Nota, non sto parlando di spreco di spazio su disco poiché la maggior parte delle persone afferma che lo spazio su disco è così economico da essere essenzialmente libero. La memoria, tuttavia, è costosa e merita di essere apprezzata. L'uso di un numero intero a 4 byte per la chiave consente di risparmiare una grande quantità di memoria se si considera la lunghezza media del nome di circa 15 caratteri.

Tangenziale alla domanda su come e perché le chiavi possono cambiare è la domanda sul perché scegliere chiavi naturali piuttosto che chiavi surrogate, che è una domanda interessante e forse più importante, specialmente dove le prestazioni sono un obiettivo di progettazione. Vedi la mia domanda qui a riguardo.


1 - http://weblogs.sqlteam.com/mladenp/archive/2009/10/06/Why-I-prefer-surrogate-keys-instead-of-natural-keys-in.aspx


3
Per evitare CASCADE (che presenta problemi in alcuni scenari) potresti anche rendere nulle le colonne FK, quindi se hai bisogno di cambiare il PK, puoi aggiornare le righe relative a NULL (in blocchi, se ce ne sono molte, o per tabella , se sono presenti molte tabelle o entrambe), quindi modificare il valore PK, quindi modificare nuovamente gli FK.
Aaron Bertrand

8

Mentre puoi usare una chiave naturale e / o mutabile come il tuo PK, nella mia esperienza che porta a problemi, che spesso possono essere prevenuti con l'uso di un PK che soddisfa queste condizioni:

 Guaranteed Unique, Always Exists, Immutable, and Concise.

Ad esempio, molte aziende negli Stati Uniti cercano di utilizzare i numeri di previdenza sociale come numeri di identificazione personale (e PK) nei loro sistemi. Quindi incontrano i seguenti problemi: errori di immissione dei dati che portano a più record che devono essere riparati, persone che non hanno un SSN, persone il cui SSN è cambiato dal governo, persone che hanno SSN duplicati.

Ho visto ognuno di quegli scenari. Ho anche visto aziende che non volevano che i loro clienti fossero "solo un numero", il che significava che il loro PK finiva per essere "primo + medio + ultimo + DOB + zip" o qualche assurdità simile. Sebbene abbiano aggiunto abbastanza campi per garantire quasi l'unicità, le loro query erano orrende e aggiornare uno di quei campi significava inseguire problemi di coerenza dei dati.

Nella mia esperienza, un PK generato dal database stesso è quasi sempre una soluzione migliore.

Consiglio questo articolo per ulteriori suggerimenti: http://www.agiledata.org/essays/keys.html


6
Un buon consiglio dall'articolo di Scott Ambler a cui si fa riferimento nella tua risposta: "Alcune persone ti diranno che dovresti sempre usare chiavi naturali e altri ti diranno che dovresti sempre usare chiavi surrogate. Queste persone invariabilmente si dimostrano sbagliate, in genere stanno facendo poco più che condividere i pregiudizi della loro "religione dei dati" con te. La realtà è che le chiavi naturali e surrogate hanno ciascuna i loro vantaggi e svantaggi e che nessuna strategia è perfetta per tutte le situazioni ".
nvogel,

7

La chiave primaria potrebbe essere modificata quando è coinvolta la sincronizzazione. Questo potrebbe essere il caso in cui si dispone di un client disconnesso e sincronizza i dati con il server a determinati intervalli.

Alcuni anni fa ho lavorato su un sistema in cui tutti i dati degli eventi sul computer locale avevano ID di riga negativi, come -1, -2, ecc. Quando i dati erano sincronizzati con il server, l'ID di riga sul server veniva applicato al cliente. Supponiamo che l'ID della riga successiva sul server sia 58. Quindi -1 diventerebbe 58, -2 59 e così via. La modifica dell'ID riga verrebbe sovrapposta a tutti i record FK figlio sul computer locale. Il meccanismo è stato anche utilizzato per determinare quali record erano stati precedentemente sincronizzati.

Non sto dicendo che questo era un buon design, ma è un esempio della chiave primaria che cambia nel tempo.


5

Qualsiasi progetto che comporta la modifica PRIMARY KEYregolare su base regolare è una ricetta per il disastro. L'unica buona ragione per cambiarlo sarebbe una fusione di due database precedentemente separati.

Come sottolineato da @MaxVernon possono verificarsi occasionali cambiamenti - quindi utilizzare ON UPDATE CASCADE, anche se la maggior parte dei sistemi oggigiorno utilizza un ID come surrogato PRIMARY KEY.

Puristi come Joe Celko e Fabian Pascal (un sito che vale la pena seguire) non sono d'accordo con l'uso di chiavi surrogate, ma penso che abbiano perso questa battaglia particolare.


3

La stabilità è una proprietà desiderabile per una chiave, ma è una cosa relativa e non una regola assoluta. In pratica è spesso utile modificare i valori delle chiavi. In termini relazionali i dati sono identificabili solo dalle sue (super) chiavi. Ne consegue che se esiste una sola chiave in una determinata tabella, la distinzione tra A) che modifica un valore chiave o B) che sostituisce l'insieme di righe in una tabella con un insieme di righe simile o diverso contenente altri valori chiave, è essenzialmente un problema di semantica piuttosto che di logica.

Un esempio più interessante è il caso di una tabella con più chiavi in ​​cui i valori di una o più di quelle chiavi potrebbero dover cambiare in relazione ad altri valori di chiave. Prendi l'esempio di una tabella Employee con due chiavi: LoginName e Badge Number. Ecco una riga di esempio da quella tabella:

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

Se ZoeS perde il suo badge, forse le viene assegnato uno nuovo e ottiene un nuovo numero di badge:

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

In seguito, potrebbe decidere di modificare il nome di accesso:

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

Entrambi i valori chiave sono cambiati, in relazione l'uno con l'altro. Si noti che non fa necessariamente alcuna differenza quale sia considerato "primario".

In pratica, l '"immutabilità", ovvero l'assoluta modifica di un valore, è irrealizzabile o almeno impossibile da verificare. Nella misura in cui il cambiamento fa la differenza, il modo più sicuro è probabilmente supporre che qualsiasi chiave (o qualsiasi attributo) debba cambiare.


Ho ridimensionato il tuo commento a causa della seguente affermazione: "In pratica" l'immutabilità ", cioè assolutamente mai cambiare un valore, è irrealizzabile o almeno impossibile da verificare." L'immutabilità È possibile ed è uno dei motivi più importanti per usare le chiavi surrogate.
Byron Jones,

3
Come fai a sapere che qualcuno non cambierà un valore chiave la prossima settimana o tra 10 anni? Puoi presumere che non lo faranno, ma non puoi realisticamente impedire che ciò accada (se sei l'unico responsabile, allora potresti creare barriere per tenere tutti gli altri in perpetuità, suppongo, ma sembra un caso limite). Ciò che conta davvero è che i cambiamenti sono molto rari, non che non accadranno mai.
nvogel,

3

È interessante notare che la domanda collegata sul tipo di ROWGUID fornisce il proprio caso d'uso: quando si hanno chiavi primarie in conflitto nei database che devono essere sincronizzate. Se hai due database che devono essere riconciliati e usano sequenze per le chiavi primarie, ti consigliamo di cambiare una delle chiavi in ​​modo che possa rimanere unica.

In un mondo ideale, ciò non accadrebbe mai. Per iniziare, utilizzare i GUID per le chiavi primarie. Realisticamente, tuttavia, potresti non avere nemmeno un database distribuito quando inizi a progettare e convertirlo in GUID potrebbe essere stato uno sforzo a cui è stata data la priorità di seguito per renderlo distribuito perché era considerato un impatto maggiore rispetto all'implementazione dell'aggiornamento chiave. Ciò può accadere se si dispone di una base di codice di grandi dimensioni che dipende da chiavi intere e richiederebbe una revisione importante per la conversione in GUID. C'è anche il fatto che i GUID sparsi (GUID che non sono molto vicini tra loro, cosa che accade se li si genera in modo casuale come si dovrebbe) possono causare problemi anche a determinati tipi di indici, il che significa che si desidera evitare di utilizzare come chiavi primarie (menzionate da Byron Jones ).


0

Uno scenario possibile è supponiamo che tu abbia affiliati che hanno un ID univoco e sai che non si duplicheranno tra gli affiliati poiché hanno un carattere iniziale univoco. Gli affiliati caricano i dati su una tabella principale. I record vengono elaborati e quindi assegnato un ID principale. Gli utenti devono accedere ai record non appena vengono caricati anche se non sono ancora stati elaborati. Volete che l'ID master sia basato sull'ordine elaborato e non elaborerete sempre nell'ordine in cui sono stati caricati i record. Conosco un po 'fabbricato.


-1

Immagina una situazione come quando qualcuno ha scelto il National Insurance Number (NIN) come chiave primaria e in qualche modo un operatore inserisce una riga con il NIN sbagliato. Dopo aver inserito il valore, ci sono due modi per correggere l'errore:

  1. Elimina il record errato e inserirne uno nuovo
  2. Aggiorna il valore con quello corretto e usa On Update Cascade se esiste un vincolo di integrità referenziale su quella colonna
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.