为什么在生成行计数时 @@Rowcount 中不包含 Include Actual Execution Plan?

Sha*_*eis 2 sql-server sql-server-2012

在最后一天更新表中的列时,我们的高级 DBA 向我展示了一种减少读取和争用的新技术。

伪代码是

WHILE 
  [always true condition] 
BEGIN 
  UPDATE [...]
IF @@ROWCOUNT = 0 BREAK;
END
Run Code Online (Sandbox Code Playgroud)

但是,在运行此程序时,我不小心将“包含实际执行计划”留在了“消息”选项卡中,因此我看到重复出现此情况:

(1000 row(s) affected)

(1 row(s) affected)
Run Code Online (Sandbox Code Playgroud)

但是代码有效并且 WHILE 循环有效!

我的问题是,如果包括实际执行计划返回 1 行受影响,这不应该创建一个无限循环吗?

为什么没有被计算在内?

示例表如下:

USE [tempdb];
GO

CREATE TABLE [dbo].[UpdateMePlease]
([ID] INT IDENTITY(1, 1), [UselessNote] VARCHAR(10) DEFAULT 'Delete me!', [UpdateValue] VARCHAR(10) NULL)
GO

INSERT INTO [dbo].[UpdateMePlease] ([UselessNote]) DEFAULT VALUES;
GO 10000

SELECT * FROM [dbo].[UpdateMePlease];

/* turn Actual Execution Plan on here */

WHILE 1 = 1 BEGIN

UPDATE TOP (1000) [dbo].[UpdateMePlease]
SET [UpdateValue] = [UselessNote]
WHERE [UpdateValue] IS NULL;

IF @@ROWCOUNT = 0 BREAK

END

-- Clean up
DROP TABLE [dbo].[UpdateMePlease];
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 7

DONE_IN_PROC从执行计划的消息是完全独立的的WHILE循环,是不是在你的条件被检查BREAK。马丁删除了他的答案,但这在很大程度上有意为之。根据您的客户端工具是否正在检索执行计划,您的查询不应有不同的行为 - 这会很糟糕。执行计划用于监控和审查,而不是用于影响实际行为。

请注意,逆也不一定是给定的 - 并非所有将填充的东西@@ROWCOUNT都会导致DONE_IN_PROC消息,例如

DECLARE @foo int, @x varchar(32) = 'hello';
SET @foo = @@ROWCOUNT;
PRINT @foo;
Run Code Online (Sandbox Code Playgroud)

这将1在消息窗格中产生,但您不会看到1 row(s) affected.

现在,我一直非常喜欢使用SET NOCOUNT ON;,这使这个问题变得毫无意义。但似乎DONE_IN_PROC在现代版本中的影响不像我形成这个观点时那样: