灵感来自this question,其中有关于SET NOCOUNT ...
的不同观点我们应该为SQL Server使用SET NOCOUNT ON吗?如果没有,为什么不呢?
它的作用 2011年7月22日编辑6
在任何DML之后它抑制“xx行受影响”消息。这是一个结果集,当发送时,客户端必须处理它。它很小,但可以测量(见下面的答案)
对于触发器等,客户端将收到多个“受影响的xx行”,这会导致某些ORM,MS Access,JPA等出现各种错误(参见下面的编辑)
背景
一般接受的最佳实践(我想直到这个问题)是在SQL Server中的触发器和存储过程中使用SET NOCOUNT ON
。我们在任何地方都使用它,快速谷歌显示大量的SQL Server MVP也同意。
MSDN表示这可能会导致.net SQLDataAdapter。
现在,这对我来说意味着SQLDataAdapter仅限于完全简单的CRUD处理,因为它希望“n行受影响”消息匹配。所以,我不能使用:
在问题marc_s(谁知道他的SQL的东西)说不要使用它。这与我的想法不同(我认为自己在SQL方面也有所帮助)。
我可能会遗漏一些东西(随意指出明显的东西),但你们有什么想法呢?
注意:我看到这个错误已经好几年了,因为我现在不使用SQLDataAdapter。
在评论和问题后进行修改:
编辑:更多想法......
我们有多个客户端:一个可以使用C#SQLDataAdaptor,另一个可以使用Java中的nHibernate。这些可能会以SET NOCOUNT ON
的不同方式受到影响。
如果您将存储过程视为方法,那么假设某些内部处理按照您自己的目的以某种方式工作是不好的形式(反模式)。
编辑2:trigger breaking nHibernate question,其中SET NOCOUNT ON
无法设置
(不,它不是this的重复)
编辑3:更多信息,感谢我的MVP同事
编辑4:2011年5月13日
Breaks Linq 2 SQL too when not specified?
编辑5:2011年6月14日
使用表变量打破JPA,存储过程:Does JPA 2.0 support SQL Server table variables?
编辑6:2011年8月15日
SSMS“编辑行”数据网格需要SET NOCOUNT ON:Update trigger with GROUP BY
2013年3月7日编辑
来自@RemusRusanu的更深入细节:
Does SET NOCOUNT ON really make that much of a performance difference
答案 0 :(得分:213)
好的,现在我已经完成了我的研究,这是交易:
在TDS协议中,SET NOCOUNT ON
仅保存9-bytes per query,而文本“SET NOCOUNT ON”本身则高达14个字节。我曾经认为123 row(s) affected
是从一个单独的网络数据包中以纯文本形式从服务器返回的,但事实并非如此。事实上,这是一个嵌入响应中的小DONE_IN_PROC
结构。它不是一个单独的网络数据包,因此不会浪费任何往返。
我认为你几乎总是可以坚持默认的计数行为而不用担心性能。但是在某些情况下,事先计算行数会影响性能,例如只向前游标。在这种情况下,NOCOUNT可能是必需的。除此之外,绝对没有必要遵循“尽可能使用NOCOUNT”的座右铭。
以下是关于SET NOCOUNT
设置无关紧要的非常详细的分析:http://daleburnett.com/2014/01/everything-ever-wanted-know-set-nocount/
答案 1 :(得分:81)
我花了很多时间去寻找NOCOUNT附近的实际基准数据,所以我想我会分享一个快速摘要。
答案 2 :(得分:67)
当SET NOCOUNT为ON时,不返回计数(表示受Transact-SQL语句影响的行数)。当SET NOCOUNT为OFF时,返回计数。它与任何SELECT,INSERT,UPDATE,DELETE语句一起使用。
SET NOCOUNT的设置在执行或运行时设置,而不是在解析时设置。
SET NOCOUNT ON可提高存储过程(SP)性能。
语法:SET NOCOUNT {ON |关闭}
SET NOCOUNT ON的示例:
SET NOCOUNT OFF的示例:
答案 3 :(得分:32)
我想在某种程度上这是一个DBA与开发人员问题。
作为一个开发人员,我会说不要使用它,除非你绝对肯定 - 因为使用它可能会破坏你的ADO.NET代码(如微软记录的那样)。
我认为作为一名DBA,你会在另一方面做得更多 - 尽可能使用它,除非你真的必须阻止它的使用。
此外,如果您的开发人员曾使用ADO.NET的ExecuteNonQuery
方法调用返回的“RecordsAffected”,那么如果每个人都使用SET NOCOUNT ON
,则会遇到麻烦,因为在这种情况下,ExecuteNonQuery将始终返回0
另见Peter Bromberg的blog post并查看他的位置。
所以它真的归结为谁设定标准:-)
马克
答案 4 :(得分:11)
如果您说您可能也有不同的客户端,如果未将SET NOCOUNT设置为ON,则会出现传统ADO的问题。
我经常遇到一个问题:如果存储过程执行了许多语句(因此返回了许多“受xxx行影响”的消息),ADO似乎不会处理这个并抛出错误“无法更改Recordset对象的ActiveConnection属性,以Command对象作为源。“
所以我一般都主张将其设置为ON,除非确实有充分的理由不这样做。你可能已经找到了我需要去阅读更多内容的真正原因。
答案 5 :(得分:9)
冒着使事情变得更复杂的风险,我鼓励对我上面提到的所有人略有不同的规则:
NOCOUNT ON
设置在proc的顶部,但还总是再次SET NOCOUNT OFF
,然后再从存储中返回任何记录集PROC。 所以“通常保持nocount,除非你实际返回结果集”。我不知道这会破坏任何客户端代码的任何方式,这意味着客户端代码永远不需要了解有关proc内部的任何信息,并且它不是特别繁重。
答案 6 :(得分:5)
关于破坏NHibernate的触发器,我亲身体验过这种体验。基本上,当NH执行UPDATE时,它会受到一定数量的行影响。通过将SET NOCOUNT ON添加到触发器,您可以获得返回NH预期的行数,从而解决问题。所以是的,如果你使用NH,我肯定会建议将其关闭。
关于SP中的用法,这是个人偏好的问题。我总是关掉行数,但话说再说,无论如何都没有真正强烈的争论。
另一方面,您应该考虑远离基于SP的架构,然后您甚至不会有这个问题。
答案 7 :(得分:1)
SET NOCOUNT ON;
这行代码在SQL中用于不返回执行查询时受影响的行数。如果我们不需要受影响的行数,我们可以使用它,因为这有助于节省内存使用量并增加查询执行的速度。
答案 8 :(得分:1)
设置NOCOUNT ON; 上面的代码将在执行DML / DDL命令后将sql server引擎生成的消息停止到前端结果窗口。
为什么我们这样做? 由于SQL Server引擎需要一些资源来获取状态并生成消息,因此它被认为是Sql server engine的重载。所以我们设置了noncount消息。
答案 9 :(得分:1)
我想证明自己“ SET NOCOUNT ON”既不保存网络数据包也不保存往返行程
我在另一台主机上使用了测试SQLServer 2017(我使用了VM)
create table ttable1 (n int);
insert into ttable1 values (1),(2),(3),(4),(5),(6),(7)
go
create procedure procNoCount
as
begin
set nocount on
update ttable1 set n=10-n
end
create procedure procNormal
as
begin
update ttable1 set n=10-n
end
然后,我使用“ Wireshark”工具在端口1433上跟踪了数据包:
“捕获过滤器”按钮->“端口1433”
exec procNoCount
这是响应数据包:
0000 00 50 56 c0 00 08 00 0c 29 31 3f 75 08 00 45 00
0010 00 42 d0 ce 40 00 40 06 84 0d c0 a8 32 88 c0 a8
0020 32 01 05 99 fe a5 91 49 e5 9c be fb 85 01 50 18
0030 02 b4 e6 0e 00 00 04 01 00 1a 00 35 01 00 79 00
0040 00 00 00 fe 00 00 e0 00 00 00 00 00 00 00 00 00
exec procNormal
这是响应数据包:
0000 00 50 56 c0 00 08 00 0c 29 31 3f 75 08 00 45 00
0010 00 4f d0 ea 40 00 40 06 83 e4 c0 a8 32 88 c0 a8
0020 32 01 05 99 fe a5 91 49 e8 b1 be fb 8a 35 50 18
0030 03 02 e6 1b 00 00 04 01 00 27 00 35 01 00 ff 11
0040 00 c5 00 07 00 00 00 00 00 00 00 79 00 00 00 00
0050 fe 00 00 e0 00 00 00 00 00 00 00 00 00
在第40行上,我可以看到“ 07”,它是“受影响的行”的数量。 它包含在响应数据包中。没有多余的数据包。
但是它可以节省13个额外的字节,但可能比减少列名(例如,将'ManagingDepartment'更改为'MD')更值得
所以我认为没有理由使用它来提高性能
但是 正如其他人提到的那样,它可能会破坏ADO.NET 而且我也偶然发现了一个使用python的问题: MSSQL2008 - Pyodbc - Previous SQL was not a query
所以大概还是个好习惯...
答案 10 :(得分:0)
我不知道如何在客户端和SQL之间测试SET NOCOUNT ON,所以我测试了其他SET命令“SET TRANSACTION ISOLATION LEVEL READ UNCIMMITTED”的类似行为
我从连接发送了一个命令,更改了SQL的默认行为(READ COMMITTED),并为下一个命令进行了更改。 当我更改存储过程中的ISOLATION级别时,它不会更改下一个命令的连接行为。
目前的结论,
我认为这与其他SET命令有关,例如“SET NOCOUNT ON”
答案 11 :(得分:0)
if(set no count == off)
{ 然后它将保留受影响的记录数量的数据 所以降低性能 } 其他 { 它不会跟踪变化的记录 从而改善性能 } }
答案 12 :(得分:0)
我知道这是一个非常古老的问题。但只是为了更新。
最佳使用方式"设置NOCOUNT ON"是将它作为SP中的第一个语句并在最后一个SELECT语句之前再次设置为OFF。
答案 13 :(得分:0)
有时候,即使最简单的事情也会有所作为。 SET NOCOUNT ON
是应该成为每个存储过程的一部分的这些简单项目之一。放在存储过程顶部的这一行代码关闭了每个T-SQL语句执行后SQL Server发送回客户端的消息。这对所有SELECT
,INSERT
,UPDATE
和DELETE
语句都执行。在查询窗口中运行T-SQL语句时,拥有此信息很方便,但是在运行存储过程时,则无需将该信息传递回客户端。
通过从网络上消除这些额外的开销,可以大大提高数据库和应用程序的整体性能。
如果仍然需要获取受正在执行的T-SQL语句影响的行数,则仍可以使用@@ROWCOUNT
选项。通过发出SET NOCOUNT ON
,此函数(@@ROWCOUNT
)仍然有效,并且仍可以在存储过程中使用,以标识该语句影响了多少行。
答案 14 :(得分:0)
SET NOCOUNT ON
真正可以帮助的一个地方是您在循环或游标中进行查询的地方。这可能会增加大量网络流量。
CREATE PROCEDURE NoCountOn
AS
set nocount on
DECLARE @num INT = 10000
while @num > 0
begin
update MyTable SET SomeColumn=SomeColumn
set @num = @num - 1
end
GO
CREATE PROCEDURE NoCountOff
AS
set nocount off
DECLARE @num INT = 10000
while @num > 0
begin
update MyTable SET SomeColumn=SomeColumn
set @num = @num - 1
end
GO
在SSMS中打开客户端统计信息,运行EXEC NoCountOn
和EXEC NoCountOff
显示NoCountOff上有一个额外的390KB流量:
在循环或游标中执行查询可能不理想,但我们也不是生活在理想的世界中:)
答案 15 :(得分:0)
SET NOCOUNT ON甚至可以访问受影响的行,如下所示:
SET NOCOUNT ON
DECLARE @test TABLE (ID int)
INSERT INTO @test
VALUES (1),(2),(3)
DECLARE @affectedRows int = -99
DELETE top (1)
FROM @test
SET @affectedRows = @@rowcount
SELECT @affectedRows as affectedRows
结果
受影响的行
1
消息
命令成功完成。
完成时间:2020-06-18T16:20:16.9686874 + 02:00
答案 16 :(得分:0)