如何批量更新SQL表?
我已经花了一些时间试图弄明白这一点,但我仍然有点卡住了,我不能真正找到在线解决方案,因为我认为我错过了关键字 我想批量更新一个SQL表,这意味着我有几百万个条目,并想一步一步地更新索引0-999、1000-1999,以避免巨大的数据库锁定 这就是我发现的:如何批量更新SQL表?,sql,tsql,Sql,Tsql,我已经花了一些时间试图弄明白这一点,但我仍然有点卡住了,我不能真正找到在线解决方案,因为我认为我错过了关键字 我想批量更新一个SQL表,这意味着我有几百万个条目,并想一步一步地更新索引0-999、1000-1999,以避免巨大的数据库锁定 这就是我发现的: DECLARE @Rows INT, @BatchSize INT; SET @BatchSize = 2500; SET @Rows = @BatchSize; WHILE (@Rows = @BatchSize) BE
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索引而不是每次都简单地针对相同的行来进行实际操作?您需要一些限制因素来决定每个循环中哪些行被命中。通常,您将使用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替换为表架构中效果最好的字段
请注意,如果在update查询中有某种WHERE子句阻止返回相同的行,那么您的方法将起作用
例如,更新表集合id=1,其中id=2不会在第二次执行中提取相同的行您只是在更新相同的行。需要一个和 左会合?如果您真的想分配空值,那么使用单独的更新
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;
一种方法是使用带有行号的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条记录。mysql tsql..由于代码看起来像tsql,我删除了mysql标记。TOP N和no order by,可以选择相同的TOP N-更新后,没有任何内容会改变该行以将其从TopN的下一次迭代中排除,我可以看到第一次迭代0到2500,第二次迭代,2500到5000-第2500行上有一个双行,因为中间是包含在内的,虽然我认为这对这个示例不重要,但值得注意。