受到这个问题的启发,关于SET NOCOUNT有不同的观点…

我们应该使用SET NOCOUNT ON SQL Server吗?如果不是,为什么不是?

它的作用编辑6,2011年7月22日

它在任何DML之后抑制“受影响的xx行”消息。这是一个结果集,当发送时,客户端必须处理它。它很小,但可测量(见下面的答案)

对于触发器等,客户端将收到多个“受影响的xx行”,这将导致一些orm, MS Access, JPA等的各种错误(见下面的编辑)

背景:

一般公认的最佳实践(我认为直到这个问题)是在SQL Server的触发器和存储过程中使用SET NOCOUNT ON。我们到处使用它,快速谷歌显示大量的SQL Server mvp也同意。

MSDN说这会破坏。net SQLDataAdapter。

现在,这对我来说意味着SQLDataAdapter仅限于完全简单的CRUD处理,因为它期望匹配“受影响的n行”消息。所以,我不能用:

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

在这个问题中marc_s(谁知道他的SQL东西)说不要使用它。这与我的想法不同(我认为自己在SQL方面也有一定的能力)。

我可能遗漏了一些东西(尽管指出显而易见的事实),但你们怎么看?

注意:我已经好几年没有看到这个错误了,因为我现在不使用SQLDataAdapter。

评论和问题后的编辑:

编辑:更多想法…

我们有多个客户端:一个可能使用c# SQLDataAdaptor,另一个可能使用来自Java的nHibernate。这些可以通过SET NOCOUNT ON以不同的方式受到影响。

如果您将存储的proc视为方法,那么假定某些内部处理以某种方式为您自己的目的是不合适的(反模式)。

编辑2:一个触发中断nHibernate问题,其中SET NOCOUNT ON不能设置

(不,它不是这个的副本)

编辑3:更多信息,感谢我的MVP同事

KB 240882,在SQL 2000和更早的版本上导致断开连接的问题 性能增益演示

编辑4:2011年5月13日

打破linq2 SQL太当没有指定?

编辑5:14 2011年6月

打破JPA,存储过程与表变量:JPA 2.0支持SQL Server表变量吗?

编辑6:15 2011年8月

SSMS“编辑行”数据网格需要SET NOCOUNT ON:用GROUP BY更新触发器

编辑7: 07 Mar 2013

更深入的细节来自@RemusRusanu: SET NOCOUNT ON真的有这么大的性能差异吗


当前回答

如果你说你可能有不同的客户端,经典的ADO有问题,如果SET NOCOUNT没有设置为ON。

我经常遇到的一个问题是:如果一个存储过程执行了许多语句(因此返回了许多“受影响的xxx行”消息),ADO似乎没有处理这个问题,并抛出错误“无法更改以Command对象作为源的记录集对象的ActiveConnection属性”。

所以我一般建议打开它,除非有非常非常好的理由不打开。你可能已经找到了非常非常好的理由,我需要进一步阅读。

其他回答

Sometimes even the simplest things can make a difference. One of these simple items that should be part of every stored procedure is SET NOCOUNT ON. This one line of code, put at the top of a stored procedure turns off the messages that SQL Server sends back to the client after each T-SQL statement is executed. This is performed for all SELECT, INSERT, UPDATE, and DELETE statements. Having this information is handy when you run a T-SQL statement in a query window, but when stored procedures are run there is no need for this information to be passed back to the client.

通过从网络中移除这种额外的开销,可以极大地提高数据库和应用程序的整体性能。

如果您仍然需要获得受正在执行的T-SQL语句影响的行数,您仍然可以使用@@ROWCOUNT选项。通过发出SET NOCOUNT ON,这个函数(@@ROWCOUNT)仍然可以工作,并且仍然可以在存储过程中使用,以确定有多少行受到语句的影响。

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流量:

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

SET NOCOUNT ON-将显示“Command(s) completed successfully”。 SET NOCOUNT OFF-它将显示”(No。受影响的行)”。

我想在某种程度上这是一个DBA vs.开发人员的问题。

作为一个开发人员,我会说除非你绝对有必要,否则不要使用它——因为使用它会破坏你的ADO。NET代码(如Microsoft文档所示)。

我想作为一名DBA,您应该站在另一边——只要有可能就使用它,除非您真的必须阻止它的使用。

同样,如果你的开发者使用了ADO返回的“RecordsAffected”。NET的ExecuteNonQuery方法调用,如果每个人都使用SET NOCOUNT ON,您就会遇到麻烦,因为在这种情况下,ExecuteNonQuery总是返回0。

也可以看看Peter Bromberg的博客文章,看看他的立场。

所以归根结底是谁来制定标准:-)

Marc

为了找到关于NOCOUNT的真实基准数据,我花了很多时间进行挖掘,所以我想分享一个简短的总结。

If your stored procedure uses a cursor to perform a lot of very quick operations with no returned results, having NOCOUNT OFF can take roughly 10 times as long as having it ON. 1 This is the worst-case scenario. If your stored procedure only performs a single quick operation with no returned results, setting NOCOUNT ON might yield around a 3% performance boost. 2 This would be consistent with a typical insert or update procedure. (See the comments on this answer for some discussion about why this may not always be faster.) If your stored procedure returns results (i.e. you SELECT something), the performance difference will diminish proportionately with the size of the result set.