SQLMenace имеет правильный ответ.
Если таблица просто огромна, то изменение может занять некоторое время и может блокировать в течение длительного времени.Если это так, и ваша база данных не может терпеть длительное время простоя для этой таблицы (возможно, это 24-часовой OLTP?), Я предлагаю сделать что-то вроде этого:
--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;
Мой сценарий не проверен... может быть, это хорошая идея, чтобы проверить это в первую очередь.:)
Выполнение обновления в пакетном режиме сохраняет размер транзакции небольшим, предотвращает чрезмерное использование базы данных tempdb, рост объема транзакций и длительные блокировки (таблица может использоваться другими клиентами между циклами обновления).10k часто - хороший размер, но иногда могут потребоваться меньшие числа в зависимости от того, сколько времени это займет.В идеале вы должны выбрать размер, который бы занимал значительную часть памяти, но не выдавливал кого-либо другого и использовал мало или вообще не использовал tempdb.С помощью такой циклической стратегии я сократил многочасовые обновления для огромных таблиц до нескольких минут (и что более важно, неблокирующих минут).
Примечание: для тех, кто экспериментирует сПри выполнении этой стратегии предложенный мной некластеризованный индекс больше всего поможет во время транзакции в скрипте.Для просто огромной таблицы может помочь другой некластеризованный индекс:
CREATE NONCLUSTERED INDEX IX_TableName_NewColumnName_Null ON dbo.TableName (NewColumName)
WHERE NewColumnName IS NULL; -- SQL 2008 and up only
С другой стороны, добавление исходного некластеризованного индекса может занять больше времени, если это будет сделано после обновления данных нового столбца или, возможно, блока.Или это может не занять много времени вообще.Эксперименты в порядке.