设置NOCOUNT ON使用情况

时间:2009-09-27 14:52:29

标签: sql sql-server tsql ado.net concurrency

灵感来自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行受影响”消息匹配。所以,我不能使用:

  • IF EXISTS以避免重复(没有行影响消息)注意:谨慎使用
  • 不存在(预期行数减少
  • 过滤掉琐碎的更新(例如,实际上没有数据发生变化)
  • 之前进行任何表访问(例如记录)
  • 隐藏复杂性或denormlisation

在问题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

17 个答案:

答案 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附近的实际基准数据,所以我想我会分享一个快速摘要。

  • 如果您的存储过程使用游标执行大量非常快速的操作而没有返回结果,那么使用NOCOUNT OFF可能需要大约10倍的启用时间。 1 这是最糟糕的情况。
  • 如果您的存储过程仅执行单个快速操作且未返回结果,则将NOCOUNT设置为ON将使性能提升约3%。 2 这与典型的插入或更新程序一致。
  • 如果您的存储过程返回结果(即您选择某些内容),性能差异将与结果集的大小成比例地减少。

答案 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的示例:

enter image description here

SET NOCOUNT OFF的示例:

enter image description here

答案 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)

冒着使事情变得更复杂的风险,我鼓励对我上面提到的所有人略有不同的规则:

  • 在proc中执行任何工作之前始终将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级别时,它不会更改下一个命令的连接行为。

目前的结论,

  1. 更改存储过程内的设置不会更改连接默认设置。
  2. 通过使用ADOCOnnection发送命令来更改设置会更改默认行为。
  3. 我认为这与其他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发送回客户端的消息。这对所有SELECTINSERTUPDATEDELETE语句都执行。在查询窗口中运行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 NoCountOnEXEC NoCountOff显示NoCountOff上有一个额外的390KB流量:

client statistics

在循环或游标中执行查询可能不理想,但我们也不是生活在理想的世界中:)

答案 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)

  • SET NOCOUNT ON--将显示“命令已成功完成”。
  • 将NOCOUNT设置为OFF-它将显示“((受影响的行数))”。