2016-03-07 24 views
0

我们正试图运行一个WHILE循环中的一个DELETE声明(避免大事务日志大量的行)如下:@@ ROWCOUNT的初始值跨数据库和服务器的变化

WHILE (@@ROWCOUNT > 0) 
    BEGIN 
     DELETE TOP (250000) 
     FROM 
      MYDATABASE.MYSCHEMA.MYTABLE 
     WHERE 
      MYDATABASE.MYSCHEMA.MYTABLE.DATE_KEY = 20160301 
    END 

当这命令在我们的开发环境中的新SQL Server Management Studio连接中执行,它会删除250K块中的行,这是预期的行为。

当这个命令被以同样的方式我们测试服务器上执行,我们得到

Command completed successfully 

也就是说,已运行的语句时没有输入WHILE循环的消息。

经过一些额外的调查后,我们发现行为也取决于我们连接到的数据库。因此,如果代码运行时(在我们的测试环境中),而SQL Server Management Studio连接到MYDATABASE时,DELETE语句不运行。如果我们在连接到SOME_OTHER_DATABASE的情况下运行代码,它会执行。

我们部分怀疑@@ROWCOUNT的值不可靠,并且可能因不同的连接而不同。但是,当我们为每个数据库服务器组合多次运行代码时,我们会看到100%一致的行为。因此,@@ROWCOUNT的随机初始值不会解释事情。

有关可能会发生什么的任何建议?谢谢你的帮助!

编辑#1

对于询问的@@ROWCOUNT的初始值,它是从哪里来的,我们不知道。但是在某些情况下,@@ROWCOUNT肯定被初始化为零以上的某个值,因为代码按原样在新连接上工作。

编辑#2

对于那些提出我们自己的变量声明,因为我们是通过编程语言包装只允许一个语句的执行在同一时间执行SQL命令我们的特定应用(即一个分号)。

我们曾试图通过循环之前执行一个delete语句建立的@@ROWCOUNT值:

声明#1:

DELETE TOP (250000) 
FROM 
    MYDATABASE.MYSCHEMA.MYTABLE 
WHERE 
    MYDATABASE.MYSCHEMA.MYTABLE.DATE_KEY = 20160301 

声明#2(@@ROWCOUNT大概是现在250,000):

WHILE (@@ROWCOUNT > 0) 
    BEGIN 
     DELETE TOP (250000) 
     FROM 
      MYDATABASE.MYSCHEMA.MYTABLE 
     WHERE 
      MYDATABASE.MYSCHEMA.MYTABLE.DATE_KEY = 20160301 
    END 

然而,无论是造成@@ROWCOUNT采取在启动不同的值也是在命令之间创建值。所以在某些情况下,第二条语句从不执行。

回答

2

在设置其值之前,不应使用变量。对于系统变量也是如此。

您拥有的代码非常危险。有人可以在delete之后添加诸如SELECT 'Here I am in the loop'之类的内容,并且它会中断。

更好的方法?使用你自己的变量:

DELCARE @RC int; 
WHILE (@RC > 0 OR @RC IS NULL) 
    BEGIN 
     DELETE TOP (250000) 
     FROM MYDATABASE.MYSCHEMA.MYTABLE 
     WHERE MYDATABASE.MYSCHEMA.MYTABLE.DATE_KEY = 20160301; 

     SET @RC = @@ROWCOUNT; 
    END; 
0

你在哪里得到你的初始@@ROWCOUNT从?我的意思是,你永远不会进入该块,因为@@ROWCOUNT预计为零,所以你永远不会进入循环。此外,在250K批次中删除不会改变事务日志的大小 - 如果您正在记录日志,所有删除操作都将被记录下来,因此在循环中执行此操作没有任何好处(也有一些处罚)。

+0

我的印象是事务日志在每个'BEGIN' ...'END'块之后被清除。对于涉及数千万条记录的较低开销删除语句,您会采用什么方法? – wk2752

+0

不是。事务日志保留,以便您可以构建完整的备份。做一个完整的备份告诉SQL Server你有一个新的起点,所以它可以清空那个事务日志。如果你不想*交易,你可以'截断日志',但是......我想这不是一个好主意。 –

0

你是否追踪了会话?由于@@ROWCOUNT返回会话中先前语句影响的行数,我猜想最后一个查询SSMS作为建立会话的一部分执行会返回两个环境中不同数量的行,或者您有一个登录触发器其最后一条语句返回不同行数的一个或另一个环境。无论哪种方式,痕迹都应该告诉你为什么行为是不同的。

从根本上说,虽然,这是没有意义的参考@@ROWCOUNT你运行你有兴趣获得一算语句之前。使用变量很容易解决这个问题

DECLARE cnt integer = -1; 
WHILE (cnt != 0) 
BEGIN 
    DELETE TOP (250000) 
    FROM MYDATABASE.MYSCHEMA.MYTABLE 
    WHERE MYDATABASE.MYSCHEMA.MYTABLE.DATE_KEY = 20160301; 
    SET cnt = @@ROWCOUNT; 
END