Sql server 更新十亿行表

Sql server 更新十亿行表,sql-server,database-performance,bulkupdate,Sql Server,Database Performance,Bulkupdate,我们有一个10亿行的表。我们只想将所有行的两列更新为NULL。我们试图分批完成这项工作。但是,我们关心的是性能问题。我们在这个表上有聚集的列存储索引。在这三列上创建复合非聚集索引会有帮助吗?或者我们可以将表重新加载到新表并交换表吗 任何输入都将非常有用 DECLARE @notNULLRecordsCount INT; SET @notNULLRecordsCount = 1; WHILE @notNULLRecordsCount > 0 BEGIN BEGIN

我们有一个10亿行的表。我们只想将所有行的两列更新为NULL。我们试图分批完成这项工作。但是,我们关心的是性能问题。我们在这个表上有聚集的列存储索引。在这三列上创建复合非聚集索引会有帮助吗?或者我们可以将表重新加载到新表并交换表吗

任何输入都将非常有用

DECLARE @notNULLRecordsCount INT; 

SET @notNULLRecordsCount = 1;

WHILE @notNULLRecordsCount > 0 
    BEGIN 
    BEGIN TRANSACTION;

    UPDATE  TOP (100000)
    dbo.BillionRowsTable
    SET     Column1 = NULL,
            Column2 = NULL,
            Column3 = NULL     
    WHERE   Column1 IS NOT NULL OR Column2 IS NOT NULL OR Column3 IS NOT NULL;


SET @notNULLRecordsCount = @@ROWCOUNT;
COMMIT TRANSACTION;
END 

我的经验是,索引实际上会减慢速度,因为必须维护索引

让交易保持开放状态是不好的。将所有这些都打包到事务中是不好的。如果你打算将它们全部打包在一个事务中,那么就没有拆散它们的目的

如果您只需输入一列(无
),速度会更快

你可以缩短这个

select 1;
WHILE @@ROWCOUNT > 0 
BEGIN 
    UPDATE  TOP (100000)
    dbo.BillionRowsTable
    SET     Column1 = NULL,
            Column2 = NULL,
            Column3 = NULL     
    WHERE   Column1 IS NOT NULL 
         OR Column2 IS NOT NULL 
         OR Column3 IS NOT NULL
END
要摆脱

select 1;
WHILE @@ROWCOUNT > 0 
BEGIN 
    UPDATE  TOP (100000)
    dbo.BillionRowsTable
    SET     Column1 = NULL,
            Column2 = NULL,
            Column3 = NULL     
    WHERE   Column1 IS NOT NULL
END

select 1;
WHILE @@ROWCOUNT > 0 
BEGIN 
    UPDATE  TOP (100000)
    dbo.BillionRowsTable
    SET     Column2 = NULL,
            Column3 = NULL     
    WHERE   Column2 IS NOT NULL
END

select 1;
WHILE @@ROWCOUNT > 0 
BEGIN 
    UPDATE  TOP (100000)
    dbo.BillionRowsTable
    SET     Column3 = NULL     
    WHERE   Column3 IS NOT NULL
END

我的经验是,索引实际上会减慢速度,因为必须维护索引

让交易保持开放状态是不好的。将所有这些都打包到事务中是不好的。如果你打算将它们全部打包在一个事务中,那么就没有拆散它们的目的

如果您只需输入一列(无
),速度会更快

你可以缩短这个

select 1;
WHILE @@ROWCOUNT > 0 
BEGIN 
    UPDATE  TOP (100000)
    dbo.BillionRowsTable
    SET     Column1 = NULL,
            Column2 = NULL,
            Column3 = NULL     
    WHERE   Column1 IS NOT NULL 
         OR Column2 IS NOT NULL 
         OR Column3 IS NOT NULL
END
要摆脱

select 1;
WHILE @@ROWCOUNT > 0 
BEGIN 
    UPDATE  TOP (100000)
    dbo.BillionRowsTable
    SET     Column1 = NULL,
            Column2 = NULL,
            Column3 = NULL     
    WHERE   Column1 IS NOT NULL
END

select 1;
WHILE @@ROWCOUNT > 0 
BEGIN 
    UPDATE  TOP (100000)
    dbo.BillionRowsTable
    SET     Column2 = NULL,
            Column3 = NULL     
    WHERE   Column2 IS NOT NULL
END

select 1;
WHILE @@ROWCOUNT > 0 
BEGIN 
    UPDATE  TOP (100000)
    dbo.BillionRowsTable
    SET     Column3 = NULL     
    WHERE   Column3 IS NOT NULL
END

感谢@Papazzo的建议,我们决定使用单栏分两阶段进行更新。我们使用Column1作为NULL,另一个使用Column1作为notnull,这样我们就覆盖了所有的行

select 1;
WHILE @@ROWCOUNT > 0 
BEGIN 
BEGIN TRANSACTION;
    UPDATE  TOP (100000)
    dbo.BillionRowsTable
    SET     Column2 = NULL,
            Column3 = NULL     
    WHERE   Column1 IS NULL;
COMMIT TRANSACTION;
END

select 1;
WHILE @@ROWCOUNT > 0 
BEGIN 
BEGIN TRANSACTION;
    UPDATE  TOP (100000)
    dbo.BillionRowsTable
    SET     Column1= NULL,
            Column2 = NULL,
            Column3 = NULL     
    WHERE   Column1 IS NOT NULL;
COMMIT TRANSACTION;
END

感谢@Papazzo的建议,我们决定使用单栏分两阶段进行更新。我们使用Column1作为NULL,另一个使用Column1作为notnull,这样我们就覆盖了所有的行

select 1;
WHILE @@ROWCOUNT > 0 
BEGIN 
BEGIN TRANSACTION;
    UPDATE  TOP (100000)
    dbo.BillionRowsTable
    SET     Column2 = NULL,
            Column3 = NULL     
    WHERE   Column1 IS NULL;
COMMIT TRANSACTION;
END

select 1;
WHILE @@ROWCOUNT > 0 
BEGIN 
BEGIN TRANSACTION;
    UPDATE  TOP (100000)
    dbo.BillionRowsTable
    SET     Column1= NULL,
            Column2 = NULL,
            Column3 = NULL     
    WHERE   Column1 IS NOT NULL;
COMMIT TRANSACTION;
END


有一种快速的方法可以做到这一点,即添加具有所需数据类型的新列(如Column1_new),删除旧列并将Column1_new重命名为原始名称,但是,如果您不需要应用任何逻辑,并且此表上没有任何模式绑定视图,则这是当然的,而且列的顺序对您或您的应用程序并不重要您缺少
提交
回滚
。表上还有多少其他索引、约束等也可以使用(rowlock)进行尝试,但我不相信这会有帮助,但可以帮助其他人访问表,而不必在表中进行操作batches@MichaelEvanchik十亿行将淹没事务日志。@hkravitz感谢您的建议。问题是,我们使用的是基于DACPAC的部署,当模式更改时,每次部署都会尝试使用新模式创建新表,并重新加载十亿行和交换表。我们未来的DACPAC部署将失败。有一种快速的方法可以做到这一点,即添加具有所需数据类型的新列(如Column1_new),删除旧列并将Column1_new重命名为原始名称,但是,如果您不需要应用任何逻辑,并且此表上没有任何架构绑定视图,则这是当然的,而且列的顺序对您或您的应用程序并不重要您缺少
提交
回滚
。表上还有多少其他索引、约束等也可以使用(rowlock)进行尝试,但我不相信这会有帮助,但可以帮助其他人访问表,而不必在表中进行操作batches@MichaelEvanchik十亿行将淹没事务日志。@hkravitz感谢您的建议。问题是,我们使用的是基于DACPAC的部署,当模式更改时,每次部署都会尝试使用新模式创建新表,并重新加载十亿行和交换表。我们未来的DACPAC部署将失败。“选择1;”的目的是什么发球?@EricBrandt要有一个@@Rowcount好的,我知道你在那里做了什么。谢谢你为我解释清楚。此外,为了确保其他用户有机会访问该表,我使用更新(或删除)TOP(x)策略,在迭代之间的混合中添加了WAITFOR延迟'00:00:00.50'之类的内容。@EricBrandt我认为没有理由减慢它down@paparazzo当有大量的更新时,日志的强化几乎没有延迟,我们发现发生了WRITELOG等待类型。使用此WAITFOR延迟将有助于强化日志。“选择1;”的目的是什么发球?@EricBrandt要有一个@@Rowcount好的,我知道你在那里做了什么。谢谢你为我解释清楚。此外,为了确保其他用户有机会访问该表,我使用更新(或删除)TOP(x)策略,在迭代之间的混合中添加了WAITFOR延迟'00:00:00.50'之类的内容。@EricBrandt我认为没有理由减慢它down@paparazzo当有大量的更新时,日志的强化几乎没有延迟,我们发现发生了WRITELOG等待类型。等待延迟将有助于强化日志。