@@ ROWCOUNT的初始值因数据库和服务器而异

时间:2016-03-07 22:32:31

标签: sql sql-server rowcount

我们试图在DELETE循环内运行一个WHILE语句(以避免大量行的大型事务日志),如下所示:

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

development 环境中的新SQL Server Management Studio连接中执行此命令时,它会删除250K块中的行,这是预期的行为。

在我们的 test 服务器上以相同的方式执行此命令时,我们会收到消息

Command completed successfully

也就是说,在语句运行时没有输入WHILE循环。

经过一些额外的调查后,我们发现行为也会因我们连接的数据库而异。因此,如果在SQL Server Management Studio连接到MYDATABASE时运行代码(在我们的 test 环境中),则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在启动时采用不同值的任何因素也会影响命令之间的值。所以在某些情况下,第二个语句永远不会执行。

3 个答案:

答案 0 :(得分:2)

在设置其值之前,不应使用变量。系统变量同样如此。

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

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

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;

答案 1 :(得分:0)

你从哪里获得最初的@@ROWCOUNT?我的意思是,你永远不会进入那个区块,因为@@ROWCOUNT预计会为零,所以你永远不会进入循环。此外,以250K批次删除不会改变事务日志的大小 - 如果您正在记录,将记录所有删除,因此这样做没有任何好处(和一些惩罚)在一个循环中。

答案 2 :(得分: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