如何批量更新SQL表?

时间:2018-03-12 15:41:58

标签: sql tsql

我已经花了一些时间试图解决这个问题,但我仍然有点陷入困境,因为我认为我错过了关键字,因此无法在网上找到解决方案。

我想批量更新SQL表,这意味着我有几百万个条目,并希望逐步更新索引0-999,1000-1999以避免巨大的数据库锁定。

这是我发现的:

DECLARE @Rows INT,
        @BatchSize INT;

SET @BatchSize = 2500;
SET @Rows = @BatchSize;

WHILE (@Rows = @BatchSize)
BEGIN
    UPDATE TOP(@BatchSize) db1
    SET db1.attr = db2.attr
    FROM DB1 db1
    LEFT JOIN DB2 db2
    ON db1.attr2 = db2.attr2

    SET @Rows = @@ROWCOUNT;
END;

我可以看到一点点简化我的陈述,但我仍然应该清楚我是如何处理整个问题的。

但是,这个东西永远循环,当看到输出时,它改变了比数据库中更多的行。

我稍后用select语句检查了同一个循环,发现它似乎只是选择了表的第一个@BatchSize行,即使我认为它会在每次迭代时在索引中进行。

如何改变这一点,以便每次迭代实际上都通过@BatchSize索引进行改进,而不是每次只针对相同的行?

3 个答案:

答案 0 :(得分:3)

您需要一些限制因素来决定每个循环命中哪些行。通常,您将使用id字段。有很多方法可以解决它,但这是一种方式:

DECLARE @MinID int = 1;
DECLARE @MaxID int = 2500;
DECLARE @Rows int = 1;
DECLARE @Batchsize int = 2500;

WHILE (@Rows > 1)
BEGIN
       UPDATE db1
       SET db1.attr = db2.attr
       FROM DB1 db1
       LEFT JOIN DB2 db2 ON db1.attr2 = db2.attr2
       WHERE db1.ID BETWEEN @MinID AND MaxID

SET @Rows = @@ROWCOUNT
SET @MinID = MinID + @Batchsize
SET @MaxID = MaxID + @Batchsize

END

db1.ID替换为表格架构中最适合的字段。

注意,如果更新查询中有某种WHERE子句阻止返回相同的行,那么您的方法将起作用。

实施例。 UPDATE table SET id = 1 WHERE id = 2不会在第二次执行中拉出相同的行

答案 1 :(得分:0)

您只是更新相同的行。需要and <>

左连接?如果您确实要分配空值,请使用单独的更新。

DECLARE @Rows INT,
        @BatchSize INT;

SET @BatchSize = 2500;
SET @Rows = @BatchSize;

WHILE (@Rows = @BatchSize)
BEGIN
    UPDATE TOP(@BatchSize) db1
    SET db1.attr = db2.attr
    FROM DB1 db1
    JOIN DB2 db2
      ON db1.attr2 = db2.attr2 
     AND db1.attr <> db2.attr

    SET @Rows = @@ROWCOUNT;
END;

你可以这样做:

select 1
WHILE (@@ROWCOUNT > 0)
BEGIN
    UPDATE TOP(2000) db1
    SET db1.attr = db2.attr
    FROM DB1 db1
    JOIN DB2 db2
      ON db1.attr2 = db2.attr2 
     AND db1.attr <> db2.attr
END;

答案 2 :(得分:0)

一种方法是使用带有row_number的cte:

DECLARE @BatchSize int = 2500,
        @LastRowUpdated int = 0;
        @Count int


SELECT @Count = COUNT(*) FROM db1;


;WITH CTE AS
(
    SELECT  attr, 
            attr2,
            ROW_NUMBER() OVER(ORDER BY attr, atrr2) As RN
    FROM db1
)

WHILE @LastRowUpdated < @Count
BEGIN

    UPDATE c
    SET attr = db2.atrr
    FROM CTE c
    LEFT JOIN DB2 ON c.attr2 = db2.attr2
    WHERE c.RN > @LastRowUpdated
    AND c.RN < (@LastRowUpdated +1) * @BatchSize

    SELECT @LastRowUpdated += 1

END

这将在循环的每一步更新2500条记录。

相关问题