SQL Prompt教程:使用SQL Prompt查找SET NOCOUNT代码问题

SQL Prompt是一款实用的SQL语法提示工具。SQL Prompt根据数据库的对象名称、语法和代码片段自动进行检索,为用户提供合适的代码选择。自动脚本设置使代码简单易读–当开发者不大熟悉脚本时尤其有用。SQL Prompt安装即可使用,能大幅提高编码效率。此外,用户还可根据需要进行自定义,使之以预想的方式工作。

点击下载SQL Prompt正式版

SQL提示实现了两个静态代码分析规则,以检查代码是否可能滥用该SET NOCOUNT命令:
PE008 –SET NOCOUNT OFF使用
PE009 – SET NOCOUNT ONDML之前没有
无论何时执行查询,都会向客户端返回一条短消息,其中包含受该T-SQL语句影响的行数。使用时SET NOCOUNT ON,不会发送此消息。这样可以通过稍微减少网络流量来提高性能。最好SET NOCOUNT ON在SQL Server触发器和存储过程中使用,除非一个或多个使用存储过程的应用程序要求将其设置为OFF,因为它们正在读取消息中的值。SET NOCOUNT ON不会影响返回的结果。DONE_IN_PROC对于执行的每个语句,它仅抑制多余的消息信息包,否则将这些消息包作为称为的小的(九字节)消息包发送回客户端。基于服务器的逻辑以及诸如的值@@ROWCOUNT均不受影响。
默认情况下,在SQL Server实例级别SET NOCOUNT设置为OFF,这意味着DONE_IN_PROC将针对存储过程中的每个语句将消息发送到客户端。当使用提供与Microsoft SQL Server执行查询公用事业,消息“NN行受到影响”将默认,在Transact-SQL语句,如年底显示SELECT,INSERT,UPDATE,和DELETE。

Microsoft建议在会话级别上有选择地使用SET NOCOUNT ON来防止发送这些消息:“对于包含多个不返回大量实际数据的语句的存储过程,消除这些消息可以显着提高性能,因为网络通信量很大。大大减少”。

通常,最好的方法是阻止发送行计数消息(除非需要发送它们),但棘手的部分是容纳使用并经常滥用这些消息的旧版应用程序。此外,对于数据库应用程序(例如ORM)的中间层对过程的异步处理,发送这些消息有时可能会成为问题。与存储过程的结果相比,行计数消息传输到客户端的速度要慢得多,这可能会阻塞线程。

什么是讯息?

与数据库的连接分别传递数据和消息。在Management Studio(SSMS)中,当查询结果呈现为网格时,它们由查询窗口中的单独窗格表示。进行sqlClient连接时,InfoMessage处理程序可以读取消息流。为了使客户端能够读取和处理服务器发送的警告或消息,客户端可以通过可以响应这些事件的SqlInfoMessageEventHandler委托来侦听这些消息。

在本文中,我们仅关注一种类型的消息。行数。但是,SQL Server也可以发送消息以响应特定的命令。连RAISERROR(10或更低的严重程度),以及PRINT报表和SET STATISTICS语句的三人组(SET STATISTICS IO ON,SET STATISTICS TIME ON,SET STATISTICS XML ON)。我的文章《不热情的测试人员的常规SQL DML测试》说明了监视性能时使用此消息流的价值。该SET NOCOUNT命令仅确定是否发送行计数消息。

多个应用程序,组件,小部件(例如网格)和中间件(例如ORM)使用rowcount消息来获取当前数据结果的计数,即使在相同的情况下通常很难将查询与count消息进行匹配会话会执行很多其他查询,这也可能导致线程阻塞。最好在过程的返回码中或通过输出变量使用来关闭这些SET NOCOUNT ON行计数消息并使用值返回计数@@ROWCOUNT。但是,有许多旧代码需要容纳。

SET NOCOUNT设置的范围是什么?

与SQL Server建立连接并启动会话后,只需设置NOCOUNT一次,这将影响您在该会话中所做的一切。SET您所做的陈述将仅更改当前会话对特定信息的处理;您在该会话中执行的每个批处理都将继承这些设置。

如果SET在存储过程或触发器中运行语句,SET则从存储过程或触发器返回控制后,将恢复该选项的先前值。同样,如果SET NOCOUNT在动态SQL字符串中有一条通过使用sp_executesql或来运行的语句EXECUTE,则在SET执行动态SQL字符串后将还原该选项的初始值。因此,无需NOCOUNT在存储过程或触发器的末尾显式设置。

除了过程,触发器和动态执行的批处理之外,NOCOUNT会话中的所有设置都会保留在会话中,直到更改为止。

SET NOCOUNT ON的性能优势是什么?

使用精心设计的存储过程,您将只能通过覆盖的默认服务器范围设置来获得微不足道的性能提升NOCOUNT。也就是说,在特殊情况下,使用SET NOCOUNT ON将带来巨大收益。这完全取决于在过程中执行的查询的数量和频率。例如,如果某个过程正在使用游标执行许多查询,这些查询的结果随后构成返回的查询的一部分,或者该过程包含许多未返回大量实际数据的语句,则该过程可以执行与相比,速度提高了十倍NOCOUNT OFF,因为网络流量大大减少了。在过程中仅执行一两个查询,收益将不到5%。

为什么不只在数据库实例级别启用NOCOUNT?

的用户选项服务器配置设置指定“全局缺省”为每个SET选项,包括NOCOUNT。默认情况下,SQL Server实例将被NOCOUNT禁用,因此针对该实例上的数据库发出的每条语句将导致最后返回一条消息,指出受影响的行数。

您可以使用来修改实例级别的行为,从而启用NOCOUNT并阻止发送这些消息sp_configure,如清单1所示。这将影响在进行设置之后启动的所有用户会话的默认设置。
EXEC sys.sp_configure ‘user options’, ‘512’; – 512 = NOCOUNT
清单1
用户可以通过发出SET NOCOUNT仅影响其单个会话的语句来覆盖服务器级别的默认值。

触发器不应发送行数消息;这条规定没有例外。实际上,如果中间应用程序层期望某些行计数消息,并且将其SET NOCOUNT OFF用于触发器,则可能会导致奇怪的随机错误。甚至SSMS的数据网格也可能触犯触发问题。

但是,在其他地方,也有很多例外。如果您有任何旧组件使用返回的rowcount消息访问数据库,则在实例级别阻止这些消息可能会导致问题。通常,可以通过NOCOUNT针对这些组件正在使用的存储过程进行适当设置来轻松地容纳这些组件。但是,如果他们直接访问表,并且您无法SET NOCOUNT OFF为这些会话添加,则更改数据库实例级别的设置将是不明智的。

同样,如果应用程序中的某个组件(例如ORM或LINQ)正在滥用此消息来确定结果的行数,那么如果您关闭消息,则可能会发生一些不良情况。

如果您开启NOCOUNT,会有什么坏处?

如果使用DataAdaptor调用SQL Server存储过程来编辑或删除数据,请不要SET NOCOUNT ON在存储过程定义中使用。这将导致受影响的行计数返回为零,并且DataAdapter抛出DBConcurrencyException。实际上,明智的防御性编程将意味着SET NOCOUNT OFF在这些情况下发布明确的建议。

该sqlclient.sqlcommand类还可以遇到与问题SET NOCOUNT ON,可能是由客户端使用ODBC的方式造成。当应用程序调用SQLRowCount时,行计数消息在ODBC中可用。这不是可靠的信息,因为某些数据源无法在获取结果之前返回结果集中的行数。

即使在SQL Server中,仅当您NOCOUNT在读取SQLRowCount之后随后测试“状态”时,此值才可靠。当NOCOUNT选项设置为on,然后SQLROWCOUNT返回0,即使有结果。如果SQLRowCount返回0,则应用程序应通过测试特定于SQL Server的属性的值来确定是否NOCOUNT为。如果返回该值,则SQLRowCount的值为0仅表示SQL Server未返回行数。如果返回,则表示已关闭,SQLRowCount中的值为0ONSQL_SOPT_SS_NOCOUNT_STATUSSQL_NC_ONSQL_NC_OFFNOCOUNT 指示该语句不影响任何行,因此不需要处理结果。

那么,什么是“最佳实践”建议?

可行的简单建议是保持数据库实例级别的默认状态不变,并SET NOCOUNT ON在每个存储过程,触发器和动态执行的批处理的开始处添加一个。此规则将毫无例外地适用于所有触发器。存储过程也将不需要这些消息,除非被试图使用它们来获取结果行数的应用程序从数据库外部调用它们。通常,最好使用@@ RowCount中的值将计数发送到输出变量中,但这无助于预先存在的应用程序组件。如果需要确保查询返回行计数消息,则应指定它而不是采用当前设置。

SQL Prompt 使用教程>>>

猜你喜欢

转载自blog.csdn.net/RoffeyYang/article/details/113739545
今日推荐