我正在尝试运行如下所示的alter命令,除了这个表有4000万行,查询需要永远。
ALTER TABLE [dbo].[ConsumerProduct]
ADD IsPendDefault [bit] NOT NULL DEFAULT ((0))
GO
因此我考虑使用null进行更改,而不是将每列更新为4000行,并将其更改为非空。
像这样的东西
ALTER TABLE [dbo].ConsumerProduct
ADD IsPendDefault [bit] NULL
GO
SET ROWCOUNT 10000
WHILE (1=1)
BEGIN
BEGIN TRANSACTION
UPDATE ConsumerProduct
SET IsPendDefault = 0
WHERE IsPendDefault IS NULL
-- Update 1000 nonupdated rows
IF @@ROWCOUNT = 0
BEGIN
COMMIT TRANSACTION
BREAK
END
COMMIT TRANSACTION
END
ALTER TABLE [dbo].ConsumerProduct
ALTER COLUMN IsPendDefault [bit] NOT NULL
GO
即使这个查询也需要永远。是否有更简单快捷的方法来更改列中默认值的表。
我正在使用SQL Server 2012。
答案 0 :(得分:2)
在SQL Server 2012的企业版中
ALTER TABLE [dbo].[ConsumerProduct]
ADD IsPendDefault [bit] NOT NULL DEFAULT ((0))
是an online operation。所以我假设你不在EE上。
您是否确实需要将所有列值更新为0
?
一种选择是允许列可以为空,默认为NULL
ALTER TABLE [dbo].ConsumerProduct
ADD IsPendDefault [bit] NULL
并确保您的代码将NULL
视为false
。例如与SELECT ISNULL(IsPendDefault,0) AS IsPendDefault
。
如果您确实要将其设为NOT NULL
,那么分批并执行更新是最佳解决方案。但是,您希望确保每个更新都可以快速查找要更新的批处理行,而无需扫描先前批处理已更新的行。
所以(如果你有一个整数身份主键),一个选项就是简单地将其划分为你想要的批量大小的范围,并让每个批次寻求到它想要的范围。
DECLARE @I INT = 0,
@BatchSize INT = 5000;
WHILE @I <= (SELECT MAX(ID)
FROM ConsumerProduct)
BEGIN
UPDATE ConsumerProduct
SET IsPendDefault = 0
WHERE IsPendDefault IS NULL
AND ID >= @I
AND ID < @I + @BatchSize;
SET @I = @I + @BatchSize;
END
如果您的大范围是空的或者人口稀少,那么可能值得采用更精细的方法。
CREATE TABLE #processed
(
ID INT PRIMARY KEY
)
DECLARE @ID INT = 0,
@BatchSize INT = 5000;
WHILE 1 = 1
BEGIN
WITH T
AS (SELECT TOP (@BatchSize) *
FROM ConsumerProduct
WHERE ID > @ID
AND IsPendDefault IS NULL
ORDER BY ID)
UPDATE T
SET IsPendDefault = 0
OUTPUT inserted.ID
INTO #processed;
IF @@ROWCOUNT < @BatchSize
BREAK;
SELECT @ID = MAX(ID)
FROM #processed;
TRUNCATE TABLE #processed
END
DROP TABLE #processed