2013-03-21 46 views
9

我有一个非常大的表,所以我用以下命令来删除旧条目:SQL Server的批量删除使用while循环没有工作

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

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

+6

不宜日期写为''2013-01-03'',而不是为一个数字? – 2013-03-21 21:10:31

+0

有趣的是,每一个答案完全错过了。 – 2013-03-21 21:29:48

+4

另请注意,只是进行循环并不一定会降低对日志或并发的影响,具体取决于它是否是单个事务。我将停止使用@@ ROWCOUNT进行控制,在循环内添加事务,并设置一个变量= @@ ROWCOUNT。请参阅http://www.sqlperformance.com/2013/03/io-subsystem/chunk-deletes – 2013-03-21 21:37:27

回答

8

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

值你可以运行此查询先设置:

select count(*) from myTable where date < 20130103 

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

你也可以这样做:

select top 1  * from myTable 

它会去得更快。

+8

你也可以在循环之前选择1;''。 – 2013-03-21 21:33:14

27

你在这段代码之前运行什么? @@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 
4

这是因为有时@@ROWCOUNT为零下手 - 这样的while循环永远不会执行,因为它每次执行之前检查的条件,包括第一个。

这里有一个自制的do-while循环,因为SQL Server不具有内置的一个

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

SQL Server没有['WHILE'loop](http://msdn.microsoft.com/zh-cn/library/ms178642(v = sql.100).aspx)? – 2013-03-21 21:34:25

+5

@AaronBertrand他正在谈论一个'do-while'循环。如:“DO BEGIN END '(在检查条件之前总是运行一次”“)。这在SQL Server中不存在。 – EvilBob22 2013-03-21 22:06:34

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" 

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

只要确定您的删除条件和存在子句中的语句是相同的,或者您可能会遇到无限循环。

+3

请注意,在SQL 2012之后:“使用SET ROWCOUNT不会影响SQL Server未来版本中的DELETE,INSERT和UPDATE语句。避免在新开发工作中使用带有DELETE,INSERT和UPDATE语句的SET ROWCOUNT,并计划修改当前使用它的应用程序,对于类似的行为,使用TOP语法。“ – 2016-12-29 14:24:00

0

基本上,

SELECT 0 -- rowcount is 1 
WHILE (@@ROWCOUNT > 0) 
BEGIN 
    DELETE TOP (5000) FROM myTable 
    WHERE date < 20130103 
END 

或者

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