使用WHILE循环的SQL Server批量删除不起作用

时间:2013-03-21 21:04:34

标签: sql sql-server rowcount

我有一个非常大的表,所以我使用以下内容删除旧条目:

WHILE (@@ROWCOUNT > 0)
BEGIN
    DELETE TOP (5000) FROM myTable
    WHERE date < 20130103
END

我使用不同的日期运行了几次。有时它工作正常(大约需要20分钟),但有时候查询会立即完成,并且没有删除任何内容。当发生这种情况时,我只是从该表中执行一个简单的SELECT语句,然后再次尝试上面的WHILE语句,然后它就可以了!有谁知道这是为什么?我需要自动执行此查询以定期运行以控制表大小,但我想确保它在运行时实际上正确删除。谢谢。

6 个答案:

答案 0 :(得分:31)

在这段代码之前你在运行什么? @@ROWCOUNT将设置为继续执行的任何语句..如果您事先运行其他命令,则可能是0

相反,您可以强制初始计数为1

DECLARE @Rows INT
SET @Rows = 1

WHILE (@Rows > 0)
BEGIN
    DELETE TOP (5000) FROM myTable
    WHERE date < 20130103

    SET @Rows = @@ROWCOUNT
END

答案 1 :(得分:10)

据推测,原因是因为@@ROWCOUNT被初始化为值0。

您可以先运行此查询来设置它:

select count(*) from myTable where date < 20130103

这会为您的查询添加一点时间,但您会看到要删除的行数。

您还可以执行以下操作:

select top 1     * from myTable 

会更快。

答案 2 :(得分:5)

这是因为有时@@ROWCOUNT从零开始 - 所以while循环永远不会执行,因为它会在每次执行之前检查条件,包括第一个。< / p>

这是一个自制的do-while循环,因为SQL Server没有内置的。

loop:
   DELETE TOP (5000) FROM myTable
   WHERE date < 20130103
if @@ROWCOUNT > 0 goto loop

答案 3 :(得分:1)

您也可以这样编写查询:

SET ROWCOUNT 5000; -- set batch size
WHILE EXISTS (SELECT 1 FROM myTable WHERE date < '2013-01-03')
BEGIN
    DELETE FROM myTable
    WHERE date < '2013-01-03'
END;
SET ROWCOUNT 0; -- set batch size back to "no limit"

无论哪种方式,您都应该正确格式化日期字符串。

请确保您的删除条件和您的exists子句中的语句相同,否则您可能会遇到无限循环。

答案 4 :(得分:1)

基本上,

SET ROWCOUNT 5000 -- set row count to 5000
SELECT 0 -- rowcount is 1 
WHILE (@@ROWCOUNT > 0)
BEGIN
    DELETE FROM myTable
    WHERE date < 20130103
END
SET ROWCOUNT 0  -- set rowcount to unlimited

或者

shuffle_batch

答案 5 :(得分:0)

当我批量删除时,我添加一个WAITFOR DELAY(至少1或2秒)。也是我在循环外创建的第一条语句。顺便说一句,避免使用ROWCOUNT作为分隔符(https://docs.microsoft.com/en-us/sql/t-sql/statements/set-rowcount-transact-sql?view=sql-server-2017)。有两个选项:

DECLARE @BatchSize BIGINT = 50000
SET ROWCOUNT @BatchSize

DELETE 
FROM myTable 
WHERE 
date < 20130103

WHILE (@@ROWCOUNT > 0)
BEGIN
WAITFOR DELAY '00:00:02'
DELETE 
FROM myTable 
WHERE 
date < 20130103
END

DECLARE @BatchSize BIGINT = 50000

WHILE 1=1
BEGIN

    WAITFOR DELAY '00:00:02'

    DELETE TOP(@BatchSize )
    FROM myTable 
    WHERE 
    date < 20130103

    IF @@ROWCOUNT < @BatchSize 
        Break
END