J'ai une table avec une colonne d'identité qui est également une clé primaire. Actuellement, il compte 50 millions de lignes, avec la valeur la plus élevée de la colonne d'identité à 148 921 803. La table a beaucoup de DELETE
s et INSERTS
exécutés dessus, d'où la valeur élevée.
Nous voulons changer le type de données de INT
à BIGINT
pour préparer l'ajout de lignes supplémentaires. Notez qu'il n'y a aucune référence à la colonne PK.
Quelle est la meilleure façon de procéder, avec un temps d'arrêt minimal? J'ai deux options.
Comme une clé primaire est définie dans la colonne d'identité, vous ne pourrez pas modifier directement cette colonne.
Les deux approches que vous avez mentionnées dans votre question peuvent être utilisées et les temps d'arrêt dépendent de la performance de votre serveur et du nombre de lignes résidant dans ce tableau.
- Déposez le PK et modifiez la colonne; ou
Déposez d'abord le PK
/****** Object: DROP Index [PK_DatabaseLog_DatabaseLogID]******/
ALTER TABLE [dbo].[TableName] DROP CONSTRAINT [PK_TableName_ID]
GO
Modifier la colonne
ALTER TABLE [dbo].[TableName] ALTER COLUMN [dbo.ID] BIGINT
Ajouter une clé primaire
/****** Object: ADD Index [PK_DatabaseLog_DatabaseLogID]******/
ALTER TABLE [dbo].[TableName] ADD CONSTRAINT [PK_TableName_ID] PRIMARY KEY CLUSTERED
(
[ID] ASC
)
Cette approche ne prend généralement pas beaucoup de temps. Dans mon environnement, cela prend quelques secondes sur les grandes tables qui ont plus de 5 millions de lignes.
- La méthode copy-drop-rename, comme décrit
Vous pouvez également utiliser cette approche. Cependant, pour cette approche, vous avez besoin de plus de temps d'arrêt que l'approche 1 car vous devez synchroniser les tables.
Aaron Bertrand a une série en 4 parties sur ce sujet, commençant par:
Minimiser l'impact de l'élargissement d'une colonne IDENTITY - partie 1
Si vous devez absolument passer à bigint
, devez minimiser les temps d'arrêt et avoir beaucoup de temps pour la planification, l'approche qu'il documente dans la partie 4 est:
À un niveau très élevé, l'approche consiste à créer un ensemble de tables fantômes, où toutes les insertions sont dirigées vers une nouvelle copie de la table (avec le type de données plus grand), et l'existence des deux ensembles de tables est aussi transparente que possible à l'application et à ses utilisateurs.
Plus en détail, Aaron dit:
- Créez des clichés instantanés des tableaux, avec les bons types de données.
- Modifiez les procédures stockées (ou le code ad hoc) pour utiliser bigint pour les paramètres. (Cela peut nécessiter des modifications au-delà de la liste des paramètres, telles que les variables locales, les tables temporaires, etc., mais ce n'est pas le cas ici.)
- Renommez les anciennes tables et créez des vues avec les noms qui unissent les anciennes et les nouvelles tables.
- Ces vues auront au lieu de déclencheurs pour diriger correctement les opérations DML vers les tables appropriées, afin que les données puissent toujours être modifiées pendant la migration.
- Cela nécessite également que SCHEMABINDING soit supprimé de toutes les vues indexées, que les vues existantes aient des unions entre les nouvelles et les anciennes tables et que les procédures reposant sur SCOPE_IDENTITY () soient modifiées.
- Migrez les anciennes données vers les nouvelles tables par blocs.
- Nettoyage, composé de:
- Suppression des vues temporaires (ce qui supprimera les déclencheurs INSTEAD OF).
- Renommer les nouvelles tables aux noms d'origine.
- Correction des procédures stockées pour revenir à SCOPE_IDENTITY ().
- Suppression des anciennes tables désormais vides.
- Remettre SCHEMABINDING sur les vues indexées et recréer les index clusterisés.