SQLMenace a la bonne réponse.
Si la table est simplement énorme, le changement pourrait prendre un certain temps et pourrait bloquer pendant une longue période. Si oui, et votre base de données ne peut pas tolérer longtemps vers le bas pour cette table (? Peut-être est OLTP 24 heures), ma suggestion serait de faire quelque chose comme ceci:
--Add a new temporary column to store the changed value.
ALTER TABLE dbo.TableName ADD NewColumnName int NULL;
CREATE NONCLUSTERED INDEX IX_TableName_NewColumnName ON dbo.TableName (NewColumName)
INCLUDE (ColumnName); -- the include only works on SQL 2008 and up
-- This index may help or hurt performance, I'm not sure... :)
-- Update the table in batches of 10000 at a time
WHILE 1 = 1 BEGIN
UPDATE X -- Updating a derived table only works on SQL 2005 and up
SET X.NewColumnName = ColumnName
FROM (
SELECT TOP 10000 * FROM dbo.TableName WHERE NewColumnName IS NULL
) X;
IF @@RowCount = 0 BREAK;
END;
ALTER TABLE dbo.TableName ALTER COLUMN NewColumnName int NOT NULL;
BEGIN TRAN; -- now do as *little* work as possible in this blocking transaction
UPDATE T -- catch any updates that happened after we touched the row
SET T.NewColumnName = T.ColumnName
FROM dbo.TableName T WITH (TABLOCKX, HOLDLOCK)
WHERE T.NewColumnName <> T.ColumnName;
-- The lock hints ensure everyone is blocked until we do the switcheroo
EXEC sp_rename 'TableName.ColumName', 'OldColumName';
EXEC sp_rename 'TableName.NewColumnName', 'ColumName';
COMMIT TRAN;
DROP INDEX dbo.TableName.IX_TableName_NewColumnName;
ALTER TABLE dbo.TableName DROP COLUMN OldColumnName;
Mon script est non testé .. Cela pourrait être une bonne idée de le tester en premier. La mise à jour par lots réduit la taille de la transaction, empêche l'utilisation de la tempdb, la croissance du journal des tran et les longs verrous (la table peut être utilisée par d'autres clients entre chaque boucle de mise à jour). 10k est souvent une bonne taille, mais parfois des nombres plus petits peuvent être nécessaires en fonction du temps qu'il faut. Idéalement, vous choisiriez une taille qui utiliserait une bonne partie de la mémoire, mais n'écarterait personne et n'utiliserait que peu ou pas de tempdb. J'ai coupé des mises à jour multi-heures contre des tables énormes à quelques minutes (et plus important, non-bloquant minutes) avec ce genre de stratégie de bouclage. Remarque: pour ceux qui expérimentent les performances de cette stratégie, l'index non cluster que j'ai suggéré aidera plus lors de la partie transaction du script. Pour une simple énorme table, un index non cluster différent pourrait aider:
CREATE NONCLUSTERED INDEX IX_TableName_NewColumnName_Null ON dbo.TableName (NewColumName)
WHERE NewColumnName IS NULL; -- SQL 2008 and up only
D'autre part, en ajoutant l'indice nonclustered d'origine pourrait prendre plus de temps si elle est effectuée après la mise à jour des nouvelles données de colonne, ou potentiellement bloquer. Ou cela peut ne pas prendre beaucoup de temps. L'expérimentation est en ordre.