我使用以下sql查询来更新MyTable。代码需要5到15分钟。只要ROWS< = 100000000但是当Rows>时更新MyTabel 100000000需要指数时间才能更新MYTable。如何更改此代码以使用set-base而不是while循环?
VISITOR No.: <?php the_widget( "ADS-WpSiteCount" ); ?>
答案 0 :(得分:1)
这将消除循环
UPDATE MyTable
set DoorsReleased = ~DoorsReleased
WHERE LitraID = 8175
AND id BETWEEN 100000000 AND 300000000
AND DoorsReleased is not null -- if DoorsReleased is nullable
-- AND DoorsReleased <> ~DoorsReleased</strike>
如果您设置循环
以下不工作
我以为〜是列名的一部分,但它不是运算符
select 1;
WHILE (@@ROWCOUNT > 0)
BEGIN
UPDATE top (100000) MyTable
set DoorsReleased = ~DoorsReleased
WHERE LitraID = 8175
AND id BETWEEN 100000000 AND 300000000
AND ( DoorsReleased <> ~DoorsReleased
or ( DoorsReleased is null and ~DoorsReleased is not null )
)
END
在事务内部我不认为循环会有价值,因为事务日志无法清除。 10,000的批量很小。\
如评论中所述,如果你想循环然后尝试使用id作为row_number()所有这些循环是昂贵的
您可以使用OFFSET
答案 1 :(得分:1)
您的一个问题是循环中的select语句获取LitraID = 8175的所有记录,设置行号,然后在update语句中过滤。每次迭代都会发生这种情况。
这样做的一种方法是在进入循环之前获取更新的所有ID并将它们存储在临时表中。然后你可以写一个类似的查询到你拥有的那个,但加入这个id表。
但是,如果您知道有多少记录具有LitraID = 8175以及它们是否遍布整个表格,而不是与类似的ID捆绑在一起,那么还有一种更简单的方法。
DECLARE @batchSize INT
DECLARE @minId INT
DECLARE @maxId INT
SET @batchSize = 10000 --adjust according to how frequently LitraID = 8175, larger numbers if infrequent
SET @minId = 100000000
WHILE @minId <= 300000000 BEGIN
SET @maxId = @minId + @batchSize - 1
IF @maxId > 300000000 BEGIN
SET @maxId = 300000000
END
BEGIN TRANSACTION T
UPDATE MyTable
SET DoorsReleased = ~DoorsReleased
WHERE id BETWEEN @minId AND @maxId
COMMIT TRANSACTION T
SET @minId = @maxId + 1
END
这将使用id的值来控制循环,这意味着您不需要额外的步骤来计算@iterationCount。它使用小批量,因此桌子不会长时间锁定。它没有任何不必要的SELECT语句,并且假设id具有索引,更新中的WHERE子句是有效的。
它不会在每笔交易中更新完全相同的记录数量,但没有理由这样做。