Pourquoi la suppression de la propriété d'identité sur une colonne n'est pas prise en charge

11

J'ai lu qu'après SQL Server 2000, la possibilité de «désidentifier» une colonne d'identité a été supprimée. Et que c'était "By Design" (pas seulement une fonctionnalité manquante).

Voici un exemple que j'ai trouvé sur un blog . Il s'agit de mettre à jour les tables système. (Et cette capacité a été supprimée après SQL Server 2000.) Je comprends que faire cela via des tables système n'est pas une bonne idée. Je me demande simplement pourquoi une fonctionnalité permettant de faire cela d'une autre manière n'existe pas.

Travailler autour de cela va me causer beaucoup de travail. (Copie de plusieurs centaines de millions de lignes dans de nouvelles tables dans un environnement intolérant aux temps d'arrêt.)

J'ai donc pensé demander "Pourquoi".

Qu'est-ce qui a changé dans Sql Server 2005 et les versions ultérieures qui en ont fait une mauvaise chose? Ou était-ce toujours mauvais, et tout simplement pas verrouillé?

Quelle «meilleure pratique» (ou principe similaire) serait violée en faisant à nouveau d'une colonne d'identité une colonne normale?

-

Mise à jour pour répondre à la demande "pourquoi je fais cela":
Ceci est un résumé de très haut niveau: je vais commencer à ajouter des partitions à mes tables. (Pour que je puisse archiver / purger les anciennes données.) C'est très simple. Mais j'ai parfois besoin de déplacer un enregistrement vers une partition différente afin qu'il ne soit pas supprimé (lorsqu'une partition arrive pour archivage / suppression). (Je fais augmenter ma colonne de partitionnement de 2 afin qu'il y ait toujours de l'espace pour déplacer la ligne vers une autre partition.)

Mais si la colonne de partitionnement est une colonne d'identité, je dois supprimer et réinsérer la valeur (il n'y a aucun moyen de mettre à jour la valeur d'une colonne d'identité). Ce qui provoque des problèmes de réplication.

Je souhaite donc utiliser une séquence au lieu d'une colonne d'identité. Mais ce commutateur est très très difficile sur les grandes bases de données.

Vaccano
la source

Réponses:

22

Votre question est essentiellement:

Pourquoi ne puis-je plus faire cette chose risquée que je n'aurais jamais dû faire en premier lieu?

La réponse à cette question est largement hors de propos (bien que vous puissiez voir certains commentaires Microsoft dans ces éléments Connect demandant cette fonctionnalité: # 294193 et # 252226). Pour être complet, mon synopsis est le suivant: La possibilité de supprimer la propriété d'identité était un effet secondaire involontaire d'avoir la possibilité de jouer avec les tables système en premier lieu. Ce n'était pas destiné à être utilisé de nombreuses façons, souvent avec de très graves conséquences, et il a donc été supprimé. Il s'agissait d'un hack de table système non documenté et non pris en charge. La possibilité de modifier les données dans les tables système n'a pas été supprimée car Microsoft ne voulait plus que vous piratiez votre chemin pour sortir d'une colonne étant une colonne d'identité, elle a été supprimée car le nettoyage avec les tables système est extrêmement risqué. La suppression de la propriété IDENTITY en elle-même n'était pas une suppression de fonctionnalité spécifiquement ciblée, et je n'aurais jamais entièrement fait confiance à cette approche, même dans les temps anciens où c'était possible.

Cela dit, que diriez-vous de répondre à cette question à la place?

Comment supprimer la propriété IDENTITY d'une colonne avec un temps d'arrêt minimal ou nul?

Vous pouvez le faire facilement en utilisant ALTER TABLE ... SWITCHune technique que je suis certain d'avoir apprise pour la première fois de notre propre Paul White dans les solutions de contournement pour Connect # 252226 . Exemple rapide, étant donné ce tableau simple:

CREATE TABLE dbo.Original
(
  ID INT IDENTITY(1,1) PRIMARY KEY,
  name SYSNAME
);
GO

INSERT dbo.Original(name) VALUES(N'foo'),(N'bar');
GO

SELECT * FROM dbo.Original;
GO

Résultats:

ID  name
--  ----
1   foo
2   bar

Maintenant, créons un tableau fantôme et basculons dessus, puis supprimons l'ancien tableau, renommez le nouveau, puis reprenez l'activité normale:

CREATE TABLE dbo.New
(
  ID INT PRIMARY KEY,
  name SYSNAME
);
GO

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
  ALTER TABLE dbo.Original SWITCH TO dbo.New;
  DROP TABLE dbo.Original;
  EXEC sys.sp_rename N'dbo.New', N'Original', 'OBJECT';
COMMIT TRANSACTION;
GO

INSERT dbo.Original(ID,name) VALUES(3,N'splunge');
UPDATE dbo.Original SET ID = 6 WHERE ID = 1;
GO

SELECT * FROM dbo.Original;
GO

Résultats:

ID  name
--  -------
2   bar
3   splunge
6   foo

Maintenant nettoyez:

DROP TABLE dbo.Original;

Il s'agit d'une opération de métadonnées uniquement, sans mouvement de données, et ne bloquera que les autres utilisateurs pendant la mise à jour des métadonnées. Mais, certes, c'est un exemple très simpliste. Si vous avez des clés étrangères ou utilisez d'autres fonctionnalités comme la réplication, la capture de données modifiées, le suivi des modifications, etc., vous devrez peut-être désactiver ou supprimer certaines d'entre elles avant d'effectuer cette modification (je n'ai pas testé toutes les combinaisons). Pour les clés étrangères en particulier, consultez cette astuce qui montre comment générer des scripts pour supprimer et recréer toutes les contraintes de clés étrangères (ou sélectionnées).

En outre, vous devrez mettre à jour votre code d'application pour ne pas vous attendre à ce que SQL Server remplisse cette colonne et vérifier toutes les instructions d'insertion ou de sélection qui peuvent dépendre de l'ordre des colonnes ou des colonnes qu'ils doivent spécifier. En général, je saluerais toute votre base de code pour toute mention de ce tableau.

Voir également ce script d'Itzik Ben-Gan (source: cet ancien article ) pour une autre façon de gérer cela, mais il y a un mouvement de données impliqué ici, donc il ne répond pas à l'exigence de «temps d'arrêt minimal ou nul».

Aaron Bertrand
la source
3
Je voudrais encourager tous ceux qui viennent à voter pour les deux éléments de connexion. Est-il difficile d'implémenter une fonction ALTER COLUMN qui active ou désactive l'identité booléenne?! Douloureux à contourner.
usr
Je dois admettre, pour une raison quelconque, je pensais que cela ..SWITCH..ne fonctionnait que pour les tables qui avaient au moins une partition définie.
RBarryYoung du
Je veux juste ajouter que SWITCHcela ne nécessite pas Enterprise Edition, bien que le partitionnement de table le fasse.
Dan Guzman