批量更新4000万行的最佳方法

时间:2016-09-09 20:51:41

标签: sql-server tsql

基本上我需要在一个有4000万行的表上运行它,一次更新每一行会崩溃,所以我想批处理查询,这样如果它崩溃了,它可以重新运行查询,它会跳过完成批处理,然后继续留下剩余的。

UPDATE [table]
SET [New_ID] = [Old_ID]

最快的方法是什么?以下是表格的创建方式:

CREATE TABLE [table](
    [INSTANCE_ID] [int] NOT NULL,
    [table_ID] [bigint] IDENTITY(1,1) NOT NULL,
    [old_ID] [bigint] NOT NULL,
    [new_ID] [bigint] NOT NULL,
    [owner_ID] [int] NOT NULL,
    [created_time] [datetime] NULL
) ON [PRIMARY]

created_time,owner_ID也有索引。

编辑:我的更新声明完全如图所示,我只需要将old_id中的每个条目复制到new_id中,持续4000万行。

4 个答案:

答案 0 :(得分:13)

Declare @Rowcount INT = 1;

WHILE (@Rowcount > 0)   
BEGIN
        UPDATE TOP (100000) [table]   --<-- define Batch Size in TOP Clause
           SET [New_ID] = [Old_ID]
        WHERE [New_ID] <> [Old_ID]

        SET @Rowcount = @@ROWCOUNT;

       CHECKPOINT;   --<-- to commit the changes with each batch
END

答案 1 :(得分:3)

M.Ali的建议会起作用,但是当您处理40M记录时,最终会导致性能下降。我会建议一个更好的过滤器来查找每次传递中要更新的记录。这将假设您的标识列上有一个主键(或其他索引):

DECLARE @Rowcount INT = 1
    ,   @BatchSize INT = 100000
    ,   @StartingRecord BIGINT = 1;

WHILE (@Rowcount > 0)   
BEGIN
    UPDATE [table]
        SET [New_ID] = [Old_ID]
    WHERE [table_ID] BETWEEN @StartingRecord AND @StartingRecord + @BatchSize - 1;

    SET @Rowcount = @@ROWCOUNT;

    CHECKPOINT;

    SELECT @StartingRecord += @BatchSize
END

这种方法将允许每次迭代与第一次一样快。如果您没有有效的索引,则需要先修复它。

答案 2 :(得分:3)

Select 1;  -- this will set a rowcount
WHILE (@@Rowcount > 0)   
BEGIN
  UPDATE TOP (1000000) [table]   
    SET [New_ID] =  [Old_ID]
  WHERE [New_ID] <> [Old_ID] 
    or ([New_ID] is null and [Old_ID] is not null)
END

100000可能更适合顶级。

由于NewID和OldID不为null,因此不需要进行空检查。

答案 3 :(得分:2)

最快的方法是:

1)创建临时表,并使用create(select having condition)语句将旧表中的所有值插入到临时表中。

2)复制约束并刷新索引。

3)放下旧桌子。

4)将临时表重命名为原始名称。

有关此link

的完整讨论