Use SQL Prompt to find SET NOCOUNT code problems

SQL Prompt is a practical SQL syntax prompt tool. SQL Prompt automatically searches according to the object name, grammar and code fragments of the database, and provides users with appropriate code selection. Automatic script settings make the code simple and easy to read--especially useful when developers are not familiar with scripts. SQL Prompt is installed and ready to use, which can greatly improve coding efficiency. In addition, users can customize it as needed to make it work in the way expected.

SQL Prompt implements two static code analysis rules to check whether the code may abuse the SET NOCOUNT command:

  • PE008 --SET NOCOUNT OFF use
  • PE009-SET NOCOUNT ONDML not before

Whenever a query is executed, a short message will be returned to the client, which contains the number of rows affected by the T-SQL statement. When using SET NOCOUNT ON, this message will not be sent. This can improve performance by slightly reducing network traffic. It is best to use SET NOCOUNT ON in SQL Server triggers and stored procedures unless one or more applications that use stored procedures require it to be set to OFF because they are reading the value in the message. SET NOCOUNT ON will not affect the returned results. For each statement executed, DONE_IN_PROC only suppresses redundant message packets, otherwise it sends these message packets back to the client as so-called small (nine-byte) message packets. Server-based logic and values ​​such as @@ROWCOUNT are not affected.
By default, SET NOCOUNT is set to OFF at the SQL Server instance level, which means that DONE_IN_PROC will send a message to the client for each statement in the stored procedure. When using the utilities provided to execute queries with Microsoft SQL Server, the message "Line NN is affected" will default to the end of Transact-SQL statements such as SELECT, INSERT, UPDATE, and DELETE.

Microsoft recommends selectively using SET NOCOUNT ON at the session level to prevent these messages from being sent: "For stored procedures that contain multiple statements that do not return large amounts of actual data, eliminating these messages can significantly improve performance because of the large amount of network traffic .decrease very much".

In general, the best approach is to prevent sending row count messages (unless they need to be sent), but the tricky part is to accommodate older applications that use and often abuse these messages. In addition, for the asynchronous processing of the process by the middle layer of a database application (such as ORM), sending these messages may sometimes become a problem. Compared with the result of the stored procedure, the row count message is transmitted to the client much more slowly, which may block the thread.

What is a message?

The connection with the database transmits data and messages separately. In Management Studio (SSMS), when query results are presented as a grid, they are represented by separate panes in the query window. When the sqlClient connection is made, the InfoMessage handler can read the message stream. In order to enable the client to read and process warnings or messages sent by the server, the client can listen to these messages through the SqlInfoMessageEventHandler delegate that can respond to these events.

In this article, we only focus on one type of message. Rows. However, SQL Server can also send messages in response to specific commands. Even RAISERROR (severity 10 or lower), and the trio of PRINT statements and SET STATISTICS statements (SET STATISTICS IO ON, SET STATISTICS TIME ON, SET STATISTICS XML ON). My article "Regular SQL DML Testing for Unenthusiastic Testers" illustrates the value of using this message flow when monitoring performance. The SET NOCOUNT command only determines whether to send a row count message.

Multiple applications, components, widgets (such as grids) and middleware (such as ORM) use rowcount messages to obtain the current count of data results. Even in the same situation, it is often difficult to match the query with the count message. Session Many other queries are executed, which may also cause thread blocking. It is best to close these SET NOCOUNT ON row count messages in the return code of the procedure or through the use of output variables and use the value return count @@ROWCOUNT. However, there is a lot of old code that needs to be accommodated.

What is the scope of SET NOCOUNT?

After establishing a connection with SQL Server and starting a session, you only need to set NOCOUNT once, which will affect everything you do in that session. SET The statement you make will only change the processing of specific information in the current session; each batch you execute in that session will inherit these settings.

If SET runs a statement in a stored procedure or trigger, SET will restore the previous value of the option after returning control from the stored procedure or trigger. Similarly, if SET NOCOUNT has a statement EXECUTE in the dynamic SQL string that is executed by using sp_executesql or, then the initial value of the option will be restored after the SET executes the dynamic SQL string. Therefore, there is no need to explicitly set NOCOUNT at the end of the stored procedure or trigger.

Except for procedures, triggers, and dynamically executed batches, all settings in the NOCOUNT session will remain in the session until changed.

What are the performance advantages of SET NOCOUNT ON?

Using a well-designed stored procedure, you will only get a negligible performance improvement NOCOUNT by overriding the default server-wide settings. In other words, under special circumstances, using SET NOCOUNT ON will bring huge benefits. It all depends on the number and frequency of queries executed in the process. For example, if a process is using cursors to execute many queries, the results of these queries then form part of the returned query, or the process contains many statements that do not return a large amount of actual data, the process can be executed compared to the speed Ten times NOCOUNT OFF, because the network traffic is greatly reduced. Only one or two queries are executed in the process, and the revenue will be less than 5%.

Why not just enable NOCOUNT at the database instance level?

The user options server configuration settings specify "global default" for each SET option, including NOCOUNT. By default, the SQL Server instance will be disabled by NOCOUNT, so each statement issued against the database on that instance will result in a message being returned at the end indicating the number of rows affected.

You can use sp_configure to modify instance-level behavior to enable NOCOUNT and prevent these messages from being sent, as shown in Listing 1. This will affect the default settings for all user sessions started after the settings are made.
EXEC sys.sp_configure'user options', '512'; - 512 = NOCOUNT
Listing 1
Users can override the server-level default values ​​by issuing SET NOCOUNT statements that only affect their single session.

Triggers should not send row count messages; there are no exceptions to this rule. In fact, if the intermediate application layer expects certain row count messages and uses its SET NOCOUNT OFF for triggers, it may cause strange random errors. Even the data grid of SSMS may be offending the trigger problem.

However, in other places, there are many exceptions. If you have any old components that use the returned rowcount messages to access the database, blocking these messages at the instance level may cause problems. Normally, these components can be easily accommodated by proper setting of the stored procedures being used by these components through NOCOUNT. However, if they access the table directly, and you cannot add SET NOCOUNT OFF for these sessions, it would be unwise to change the database instance level settings.

Similarly, if a component in the application (such as ORM or LINQ) is abusing this message to determine the number of rows of the result, then if you turn off the message, something bad may happen.

What harm will happen if you turn on NOCOUNT?

If you use DataAdaptor to call SQL Server stored procedures to edit or delete data, please do not use SET NOCOUNT ON in the stored procedure definition. This will cause the affected row count to return to zero, and the DataAdapter throws a DBConcurrencyException. In fact, wise defensive programming will mean that SET NOCOUNT OFF issues clear recommendations in these situations.

The sqlclient.sqlcommand class can also encounter problems with SET NOCOUNT ON, which may be caused by the way the client uses ODBC. When the application calls SQLRowCount, the row count message is available in ODBC. This is not reliable information because some data sources cannot return the number of rows in the result set before the result is obtained.

Even in SQL Server, this value is only reliable if you NOCOUNT subsequently test the "state" after reading SQLRowCount. When the NOCOUNT option is set to on, then SQLROWCOUNT returns 0, even if there are results. If SQLRowCount returns 0, the application should determine whether NOCOUNT is by testing the value of the SQL Server-specific property. If this value is returned, the value of SQLRowCount of 0 only means that SQL Server has not returned the number of rows. If it returns, it means it is closed, and the value in SQLRowCount is 0ONSQL_SOPT_SS_NOCOUNT_STATUSSQL_NC_ONSQL_NC_OFFNOCOUNT indicating that the statement does not affect any rows, so there is no need to process the result.

So, what are "best practice" recommendations?

A feasible simple suggestion is to keep the default state of the database instance level unchanged, and SET NOCOUNT ON to add one at the beginning of each stored procedure, trigger, and dynamically executed batch. This rule will apply to all triggers without exception. Stored procedures will also not need these messages unless the application that is trying to use them to get the result row count calls them from outside the database. Generally, it is better to use the value in @@RowCount to send the count to the output variable, but this does not help pre-existing application components. If you need to ensure that the query returns a row count message, you should specify it instead of using the current setting.

Guess you like

Origin blog.51cto.com/15078157/2621474