set nocount on 必须置于 begin 后首行才生效,执行时动态作用于当前批处理,不影响 @@rowcount,退出后自动还原,不需配对 set nocount off。

SET NOCOUNT ON 必须放在 BEGIN 后第一行才生效
它不是全局开关,也不是编译期设置,而是在执行时动态作用于当前批处理。如果写在 DECLARE、IF 或任意 DML 语句之后,SQL Server 会忽略它——前面那些语句依然照常发送 (5 rows affected) 这类 DONE_IN_PROC 消息。
实操建议:
- 固定写法:
BEGIN换行后立刻写SET NOCOUNT ON,不加空行、不加注释干扰 - 别用
GO分割:存储过程定义体内不能出现GO,否则会提前结束批处理,导致后续语句脱离作用域 - 触发器里同样适用:触发器隐式运行在调用语句的上下文中,开头不加
SET NOCOUNT ON,外层应用可能收到意外的行计数消息
加了 SET NOCOUNT ON 会不会让 @@ROWCOUNT 失效
完全不会。@@ROWCOUNT 是 SQL Server 内部状态变量,和是否发消息给客户端无关。无论 SET NOCOUNT ON 还是 OFF,INSERT、UPDATE、DELETE 执行完后 @@ROWCOUNT 都准确更新。
这意味着你可以放心写这类逻辑:
IF @@ROWCOUNT = 0
RAISERROR('No matching record found', 16, 1);
常见误解是以为关掉行计数就“丢了行数”,其实只是没发出去而已——服务端逻辑照常运转。
为什么不能配对写 SET NOCOUNT OFF
SET NOCOUNT 的作用域只限于当前批处理(即该存储过程执行期间)。退出存储过程后,会话级的 NOCOUNT 状态自动还原,不需要、也不应该手动恢复。
强行加 SET NOCOUNT OFF 反而危险:
- 可能覆盖调用方原本设为
ON的会话设置,尤其在嵌套调用或使用连接池时 - SSIS、Power BI 等工具常依赖会话级
NOCOUNT设置,乱改会导致下游组件行为异常 - SQL Server 不报错,但副作用隐蔽,排查成本高
哪些客户端问题其实是因为漏了 SET NOCOUNT ON
这不是性能优化,而是协议层兼容性刚需。典型现象包括:
- ADO.NET 中
SqlCommand.ExecuteNonQuery()抛InvalidOperationException: There is already an open data reader associated with this command—— 多出来的行计数被当成未读结果集 - Power BI 刷新时报 “无法识别多个结果集”,尤其当存储过程含循环或多个
UPDATE - JDBC 调用后
getResultSet()返回null,因为驱动先收到了getUpdateCount() != -1的干扰信号 - EF Core 映射失败或连接意外关闭,本质是框架尝试消费所有结果集,却被冗余消息打断
真正容易被忽略的是:它不省 CPU、不省磁盘,只省 TDS 协议层的小帧。一个含 50 次 INSERT 的循环,就多发 50 次无业务价值的网络包——慢速链路或高并发下,这比查询本身还卡。











