我已经花了一些时间试图解决这个问题,但我仍然有点陷入困境,因为我认为我错过了关键字,因此无法在网上找到解决方案。
我想批量更新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索引进行改进,而不是每次只针对相同的行?
答案 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条记录。