Pourquoi une valeur de clé primaire changerait-elle?

18

J'ai fait des recherches sur le concept de ROWGUID récemment et suis tombé sur cette question. Cette réponse a donné un aperçu, mais m'a conduit dans un trou de lapin différent avec la mention de changer la valeur de la clé primaire.

Ma compréhension a toujours été qu'une clé primaire devrait être immuable, et ma recherche depuis la lecture de cette réponse n'a fourni que des réponses qui reflètent la même chose qu'une meilleure pratique.

Dans quelles circonstances une valeur de clé primaire devrait-elle être modifiée après la création de l'enregistrement?

5crammed
la source
7
Lorsqu'une clé primaire n'est pas immuable?
ypercubeᵀᴹ
2
Juste une petite note à toutes les réponses ci-dessous jusqu'à présent. La modification d'une valeur dans la clé primaire n'est pas si grave que si la clé primaire se trouve également être l'index clusterisé. Cela n'a vraiment d'importance que si les valeurs de l'index clusterisé changent.
Kenneth Fisher
6
@KennethFisher ou s'il est référencé par un (ou plusieurs) FK dans une autre table ou la même et qu'une modification doit être répercutée sur plusieurs lignes (peut-être des millions ou des milliards).
ypercubeᵀᴹ
9
Demandez à Skype. Lorsque je me suis inscrit il y a plusieurs années, j'ai mal tapé mon nom d'utilisateur (laissé une lettre hors de mon nom de famille). J'ai essayé plusieurs fois de le faire corriger, mais ils ne pouvaient pas le changer car il était utilisé pour la clé primaire et ils ne supportaient pas de le changer. C'est un cas où le client souhaite que la clé primaire soit modifiée, mais Skype ne l'a pas supporté. Ils pourraient soutenir ce changement s'ils le voulaient (ou ils pouvaient créer un meilleur design), mais il n'y a actuellement rien en place pour le permettre. Mon nom d'utilisateur est donc toujours incorrect.
Aaron Bertrand
3
Toutes les valeurs du monde réel peuvent changer (pour diverses causes). C'était l'une des motivations originales des clés de substitution / synthétiques: être capable de générer des valeurs artificielles sur lesquelles on pouvait compter pour ne jamais changer.
RBarryYoung

Réponses:

24

Si vous utilisiez le nom d'une personne comme clé primaire et que son nom change, vous devrez changer la clé primaire. C'est à cela que ON UPDATE CASCADEsert car il se répercute essentiellement sur toutes les tables liées qui ont des relations de clé étrangère avec la clé primaire.

Par exemple:

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 SELECTcontre les deux tableaux:

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

Retour:

entrez la description de l'image ici

Si nous mettons à jour la PersonKeycolonne et réexécutons 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;

nous voyons:

entrez la description de l'image ici

En regardant le plan de l' UPDATEinstruction ci-dessus , nous voyons clairement que les deux tables sont mises à jour par une seule instruction de mise à jour en vertu de la clé étrangère définie comme ON UPDATE CASCADE:

entrez la description de l'image ici cliquez sur l'image ci-dessus pour la voir plus clairement

Enfin, nous allons nettoyer nos tables temporaires:

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

La 1 façon préférée de le faire en utilisant des clés de substitution serait:

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;

Pour être complet, le plan de l'instruction de mise à jour est très simple et présente un avantage pour remplacer les clés, à savoir qu'une seule ligne doit être mise à jour par opposition à chaque ligne contenant la clé dans un scénario de clé naturelle:

entrez la description de l'image ici

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

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

Les résultats des deux SELECTinstructions ci-dessus sont:

entrez la description de l'image ici

Le résultat est essentiellement le même. Une différence majeure est que la clé naturelle large n'est pas répétée dans chaque table où se trouve la clé étrangère. Dans mon exemple, j'utilise unVARCHAR(200) colonne pour contenir le nom de la personne, ce qui nécessite d'utiliser un VARCHAR(200) partout . S'il y a beaucoup de lignes et beaucoup de tables contenant la clé étrangère, cela ajoutera beaucoup de mémoire gaspillée. Remarque, je ne parle pas de gaspillage d'espace disque car la plupart des gens disent que l'espace disque est si bon marché qu'il est essentiellement gratuit. Cependant, la mémoire coûte cher et mérite d'être chérie. L'utilisation d'un entier de 4 octets pour la clé économisera une grande quantité de mémoire si vous considérez la longueur moyenne du nom d'environ 15 caractères.

Tangentielle à la question de savoir comment et pourquoi les clés peuvent changer est la question de savoir pourquoi choisir des clés naturelles plutôt que des clés de substitution, ce qui est une question intéressante et peut-être plus importante, en particulier lorsque la performance est un objectif de conception. Voir ma question ici à ce sujet.


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

Max Vernon
la source
3
Pour éviter CASCADE (qui a des problèmes dans certains scénarios), vous pouvez également rendre les colonnes FK Nullable, donc si vous devez changer le PK, vous pouvez mettre à jour les lignes associées à NULL (en morceaux, s'il y en a beaucoup, ou par table) , s'il y a beaucoup de tables, ou les deux), puis modifiez la valeur PK, puis modifiez à nouveau les FK.
Aaron Bertrand
8

Bien que vous puissiez utiliser une clé naturelle et / ou modifiable comme votre PK, selon mon expérience, cela entraîne des problèmes, qui peuvent souvent être évités par l'utilisation d'un PK qui remplit ces conditions:

 Guaranteed Unique, Always Exists, Immutable, and Concise.

Par exemple, de nombreuses entreprises aux États-Unis essaient d'utiliser les numéros de sécurité sociale comme numéros d'identification personnels (et PK) dans leurs systèmes. Ensuite, ils rencontrent les problèmes suivants - des erreurs de saisie de données conduisant à plusieurs enregistrements qui doivent être réparés, des personnes qui n'ont pas de SSN, des personnes dont le SSN est modifié par le gouvernement, des personnes qui ont des SSN en double.

J'ai vu chacun de ces scénarios. J'ai également vu des entreprises qui ne voulaient pas que leurs clients soient "juste un numéro", ce qui signifiait que leur PK était finalement "premier + moyen + dernier + DOB + zip" ou une autre absurdité similaire. Bien qu'ils aient ajouté suffisamment de champs pour garantir presque l'unicité, leurs requêtes étaient horribles, et la mise à jour de l'un de ces champs signifiait pourchasser les problèmes de cohérence des données.

D'après mon expérience, un PK généré par la base de données elle-même est presque toujours une meilleure solution.

Je recommande cet article pour des pointeurs supplémentaires: http://www.agiledata.org/essays/keys.html

Byron Jones
la source
6
Un bon conseil de l'article de Scott Ambler référencé dans votre réponse: "Certaines personnes vous diront que vous devez toujours utiliser des clés naturelles et d'autres vous diront que vous devez toujours utiliser des clés de substitution. Ces personnes se révèlent invariablement avoir tort, généralement ils ne font guère plus que de partager avec vous les préjugés de leur "religion des données". La réalité est que les clés naturelles et de substitution ont chacune leurs avantages et leurs inconvénients, et qu'aucune stratégie n'est parfaite pour toutes les situations. "
nvogel
7

La clé primaire peut être modifiée lors de la synchronisation. Cela peut être le cas lorsque vous avez un client déconnecté et qu'il synchronise les données avec le serveur à certains intervalles.

Il y a quelques années, j'ai travaillé sur un système où toutes les données d'événement sur la machine locale avaient des ID de ligne négatifs, comme -1, -2, etc. Lorsque les données étaient synchronisées avec le serveur, l'ID de ligne sur le serveur était appliqué au client. Disons que l'ID de la ligne suivante sur le serveur était 58. Ensuite, -1 deviendrait 58, -2 59 et ainsi de suite. Ce changement d'ID de ligne serait répercuté en cascade sur tous les enregistrements FK enfants sur la machine locale. Le mécanisme a également été utilisé pour déterminer les enregistrements précédemment synchronisés.

Je ne dis pas que c'était une bonne conception, mais c'est un exemple de changement de clé primaire au fil du temps.

Jon Raynor
la source
5

Toute conception qui implique de modifier la PRIMARY KEY régulièrement le est une recette pour un désastre. La seule bonne raison de le modifier serait la fusion de deux bases de données auparavant distinctes.

Comme l'a souligné @MaxVernon, des changements occasionnels peuvent se produire - puis utiliser ON UPDATE CASCADE, bien que la majorité des systèmes utilisent de nos jours un ID comme substitut PRIMARY KEY.

Des puristes tels que Joe Celko et Fabian Pascal (un site à suivre) ne sont pas d'accord avec l'utilisation de clés de substitution, mais je pense qu'ils ont perdu cette bataille particulière.

Vérace
la source
3

La stabilité est une propriété souhaitable pour une clé, mais c'est une chose relative et non une règle absolue. En pratique, il est souvent utile de modifier les valeurs des clés. En termes relationnels, les données ne sont identifiables que par ses (super) clés. Il s'ensuit que s'il n'y a qu'une seule clé dans une table donnée, la distinction entre A) changer une valeur de clé ou B) remplacer l'ensemble de lignes dans une table par un ensemble de lignes similaires ou différentes contenant d'autres valeurs de clé, est essentiellement un problème de sémantique plutôt que de logique.

Un exemple plus intéressant est le cas d'une table ayant plusieurs clés où les valeurs d'une ou plusieurs de ces clés peuvent devoir changer par rapport à d'autres valeurs de clé. Prenons l'exemple d'une table Employé avec deux clés: LoginName et Badge Number. Voici un exemple de ligne de ce tableau:

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

Si ZoeS perd son badge, alors peut-être lui en attribue-t-on un nouveau et obtient-il un nouveau numéro de badge:

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

Plus tard, elle pourrait décider de changer son nom de connexion:

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

Les deux valeurs clés ont changé - l'une par rapport à l'autre. Notez que cela ne fait pas nécessairement de différence lequel est considéré comme "principal".

Dans la pratique, «l'immuabilité», c'est-à-dire qu'elle ne change absolument jamais une valeur, est impossible ou du moins impossible à vérifier. Dans la mesure où le changement fait une différence, le cours le plus sûr est probablement de supposer que n'importe quelle clé (ou n'importe quel attribut) pourrait devoir changer.

nvogel
la source
J'ai rétrogradé votre commentaire en raison de la déclaration suivante: "Dans la pratique," l'immuabilité ", c'est-à-dire qu'il ne change absolument jamais une valeur, est irréalisable ou du moins impossible à vérifier." L'immuabilité EST possible et est l'une des raisons les plus importantes d'utiliser des clés de substitution.
Byron Jones
3
Comment pouvez-vous savoir que quelqu'un ne changera pas de valeur clé la semaine prochaine ou dans 10 ans? Vous pouvez supposer que ce ne sera pas le cas, mais vous ne pouvez pas empêcher que cela se produise de manière réaliste (si vous êtes le seul responsable, vous pouvez mettre en place des barrières pour empêcher tout le monde de rester à perpétuité, je suppose, mais cela semble être un cas extrême). Ce qui compte vraiment, c'est que les changements sont très peu fréquents, pas qu'ils ne se produiront jamais.
nvogel
3

Chose intéressante, la question liée sur le type de ROWGUID fournit son propre cas d'utilisation: lorsque vous avez des clés primaires en conflit dans les bases de données qui doivent être synchronisées. Si vous avez deux bases de données à réconcilier et qu'elles utilisent des séquences pour les clés primaires, vous souhaiterez que l'une des clés change pour qu'elle reste unique.

Dans un monde idéal, cela n'arriverait jamais. Vous utiliseriez des GUID pour les clés primaires pour commencer. De façon réaliste, cependant, vous pourriez même ne pas avoir de base de données distribuée lorsque vous commencez à concevoir, et la convertir en GUID a peut-être été un effort qui a été priorisé ci-dessous pour la faire distribuer, car elle a été considérée comme ayant un impact plus élevé que la mise en œuvre de la mise à jour clé. Cela pourrait se produire si vous avez une grande base de code qui dépend de clés entières et nécessiterait une révision majeure pour convertir en GUID. Il y a aussi le fait que les GUID clairsemés (GUID qui ne sont pas très proches les uns des autres, ce qui se produit si vous les générez de manière aléatoire comme vous le devriez) peuvent également causer des problèmes pour certains types d'index, ce qui signifie que vous voulez éviter d'utiliser les en tant que clés primaires (mentionnées par Byron Jones ).

jpmc26
la source
0

Un scénario possible est de supposer que vous avez des affiliés qui ont un ID unique et que vous savez qu'ils ne se dupliqueront pas entre les affiliés car ils ont un caractère de départ unique. Les affiliés chargent des données dans une table principale. Ces enregistrements sont traités puis attribués à un ID maître. Les utilisateurs doivent avoir accès aux enregistrements dès qu'ils sont chargés, même s'ils ne sont pas encore traités. Vous souhaitez que l'ID maître soit basé sur la commande traitée et vous ne traiterez pas toujours dans l'ordre de chargement des enregistrements. Je sais un peu fabriqué.

paparazzo
la source
-1

Imaginez une situation comme lorsque quelqu'un a choisi le numéro d'assurance nationale (NIN) comme clé primaire et qu'un opérateur insère une ligne avec le mauvais NIN. Après avoir inséré la valeur, il existe deux façons de corriger l'erreur:

  1. Supprimer l'enregistrement erroné et en insérer un nouveau
  2. Mettez à jour la valeur vers la bonne et utilisez On Update Cascade s'il y a une contrainte d'intégrité référentielle sur cette colonne
Behrouz Sameny
la source