SET NOCOUNT ON usage

Viewed 306641

Inspired by this question where there are differing views on SET NOCOUNT...

Should we use SET NOCOUNT ON for SQL Server? If not, why not?

What it does Edit 6, on 22 Jul 2011

It suppresses the "xx rows affected" message after any DML. This is a resultset and when sent, the client must process it. It's tiny, but measurable (see answers below)

For triggers etc, the client will receive multiple "xx rows affected" and this causes all manner of errors for some ORMs, MS Access, JPA etc (see edits below)

Background:

General accepted best practice (I thought until this question) is to use SET NOCOUNT ON in triggers and stored procedures in SQL Server. We use it everywhere and a quick google shows plenty of SQL Server MVPs agreeing too.

MSDN says this can break a .net SQLDataAdapter.

Now, this means to me that the SQLDataAdapter is limited to utterly simply CRUD processing because it expects the "n rows affected" message to match. So, I can't use:

  • IF EXISTS to avoid duplicates (no rows affected message) Note: use with caution
  • WHERE NOT EXISTS (less rows then expected
  • Filter out trivial updates (eg no data actually changes)
  • Do any table access before (such as logging)
  • Hide complexity or denormlisation
  • etc

In the question marc_s (who knows his SQL stuff) says do not use it. This differs to what I think (and I regard myself as somewhat competent at SQL too).

It's possible I'm missing something (feel free to point out the obvious), but what do you folks out there think?

Note: it's been years since I saw this error because I don't use SQLDataAdapter nowadays.

Edits after comments and questions:

Edit: More thoughts...

We have multiple clients: one may use a C# SQLDataAdaptor, another may use nHibernate from Java. These can be affected in different ways with SET NOCOUNT ON.

If you regard stored procs as methods, then it's bad form (anti-pattern) to assume some internal processing works a certain way for your own purposes.

Edit 2: a trigger breaking nHibernate question, where SET NOCOUNT ON can not be set

(and no, it's not a duplicate of this)

Edit 3: Yet more info, thanks to my MVP colleague

Edit 4: 13 May 2011

Breaks Linq 2 SQL too when not specified?

Edit 5: 14 Jun 2011

Breaks JPA, stored proc with table variables: Does JPA 2.0 support SQL Server table variables?

Edit 6: 15 Aug 2011

The SSMS "Edit rows" data grid requires SET NOCOUNT ON: Update trigger with GROUP BY

Edit 7: 07 Mar 2013

More in depth details from @RemusRusanu:
Does SET NOCOUNT ON really make that much of a performance difference

17 Answers

I wanted to verify myself that 'SET NOCOUNT ON' does not save a network packet nor a roundtrip

I used a test SQLServer 2017 on another host (I used a 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 Then I traced packets on port 1433 with the tool 'Wireshark': 'capture filter' button -> 'port 1433'

exec procNoCount

this is the response packet: 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

this is the response packet: 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

On line 40 I can see '07' which is the number of 'row(s) affected'. It is included in the response packet. No extra packet.

It has however 13 extra bytes which could be saved, but probably not more worth it than reducing column names (e.g. 'ManagingDepartment' to 'MD')

So I see no reason to use it for performance

BUT As others mentioned it can break ADO.NET and I also stumbled on an issue using python: MSSQL2008 - Pyodbc - Previous SQL was not a query

So probably a good habit still...

One place that SET NOCOUNT ON can really help is where you are doing queries in a loop or a cursor. This can add up to a lot of network traffic.

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

Turning on client statistics in SSMS, a run of EXEC NoCountOn and EXEC NoCountOff shows that there was an extra 390KB traffic on the NoCountOff one:

client statistics

Probably not ideal to be doing queries in a loop or cursor, but we don't live in in ideal world either :)

  • SET NOCOUNT ON- It will show "Command(s) completed successfully".
  • SET NOCOUNT OFF- it will show "(No. Of row(s) affected)".

SET NOCOUNT ON even does allows to access to the affected rows like this:

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

Results

affectedRows

1

Messages

Commands completed successfully.

Completion time: 2020-06-18T16:20:16.9686874+02:00

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.

By removing this extra overhead from the network it can greatly improve overall performance for your database and application.

If you still need to get the number of rows affected by the T-SQL statement that is executing you can still use the @@ROWCOUNT option. By issuing a SET NOCOUNT ON this function (@@ROWCOUNT) still works and can still be used in your stored procedures to identify how many rows were affected by the statement.

Related