在最后一天更新表中的列时,我们的高级 DBA 向我展示了一种减少读取和争用的新技术。
伪代码是
WHILE
[always true condition]
BEGIN
UPDATE [...]
IF @@ROWCOUNT = 0 BREAK;
END
但是,在运行此程序时,我不小心将“包含实际执行计划”保留为打开状态,因此在“消息”选项卡中我看到了重复出现的情况:
(1000 row(s) affected)
(1 row(s) affected)
但是代码有效并且 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];
DONE_IN_PROC
来自执行计划的消息完全独立于您的循环,并且不是在WHILE
您的 conditional 中检查的内容BREAK
。马丁删除了他的答案,但这在很大程度上是设计使然。您的查询不应该根据您的客户端工具是否正在检索执行计划而表现不同——那是不好的。执行计划是为了监控和审查,而不是为了影响实际行为。请注意,反转也不一定是给定的 - 并非所有将填充的东西
@@ROWCOUNT
都会导致DONE_IN_PROC
消息,例如这将
1
在消息窗格中产生,但您不会看到1 row(s) affected.
现在,我一直是使用 的忠实
SET NOCOUNT ON;
拥护者,这使这个问题变得毫无意义。但在现代版本中,它的影响似乎DONE_IN_PROC
不像我形成这个观点时那样: