SET NOCOUNT ON sull'utilizzo


341

Ispirato da questa domanda in cui ci sono viste diverse su SET NOCOUNT ...

Dovremmo usare SET NOCOUNT ON per SQL Server? In caso contrario, perché no?

Cosa fa Modifica 6, il 22 lug 2011

Sopprime il messaggio "Righe xx interessate" dopo qualsiasi DML. Questo è un gruppo di risultati e quando viene inviato, il client deve elaborarlo. È piccolo, ma misurabile (vedi risposte sotto)

Per i trigger ecc., Il client riceverà più "righe xx interessate" e questo causerà tutti i tipi di errori per alcuni ORM, MS Access, JPA ecc. (Vedere le modifiche di seguito)

Sfondo:

Le best practice generalmente accettate (ho pensato fino a questa domanda) devono essere utilizzate SET NOCOUNT ONnei trigger e nelle stored procedure in SQL Server. Lo usiamo ovunque e un rapido google mostra anche molti MVP di SQL Server d'accordo.

MSDN dice che questo può rompere un .net SQLDataAdapter .

Ora, questo significa per me che SQLDataAdapter è limitato all'elaborazione CRUD semplicemente perché si aspetta che il messaggio "n righe interessate" corrisponda. Quindi, non posso usare:

  • SE ESISTE per evitare duplicati (nessun messaggio sulle righe interessate) Nota: utilizzare con cautela
  • DOVE NON ESISTE (meno righe del previsto
  • Filtra aggiornamenti banali (ad es. Nessun dato cambia effettivamente)
  • Effettua qualsiasi accesso alla tabella prima (come la registrazione)
  • Nascondi complessità o denormlizzazione
  • eccetera

Nella domanda marc_s (che conosce le sue cose SQL) dice di non usarlo. Ciò differisce da quello che penso (e mi considero un po 'competente anche in SQL).

È possibile che mi manchi qualcosa (sentiti libero di sottolineare l'ovvio), ma cosa ne pensi là fuori?

Nota: sono passati anni da quando ho visto questo errore perché al giorno d'oggi non uso SQLDataAdapter.

Modifiche dopo commenti e domande:

Modifica: più pensieri ...

Abbiamo più client: uno può usare un SQLDataAdaptor C #, un altro può usare nHibernate da Java. Questi possono essere influenzati in diversi modi con SET NOCOUNT ON.

Se consideri i proc memorizzati come metodi, allora è una cattiva forma (anti-pattern) supporre che l'elaborazione interna funzioni in un certo modo per i tuoi scopi.

Modifica 2: un trigger che interrompe la domanda nHibernate , dove SET NOCOUNT ONnon può essere impostato

(e no, non è un duplicato di questo )

Modifica 3: ancora più informazioni, grazie al mio collega MVP

Modifica 4: 13 maggio 2011

Rompe anche Linq 2 SQL quando non specificato?

Modifica 5: 14 giu 2011

Rompere JPA, proc memorizzato con variabili di tabella: JPA 2.0 supporta le variabili di tabella di SQL Server?

Modifica 6: 15 ago 2011

La griglia di dati "Modifica righe" di SSMS richiede SET NOCOUNT ON: Aggiorna trigger con GROUP BY

Modifica 7: 07 Mar 2013

Dettagli più dettagliati da @RemusRusanu:
SET NOCOUNT ON fa davvero molta differenza nelle prestazioni


@AlexKuznetsov: quale sarebbe un approccio "Threadsafe"? Sicuramente le letture eseguite negli EXISTS verrebbero comunque incluse eventuali transazioni in sospeso?
AnthonyWJones,

2
@Jeremy Seghi: scusa per la risposta tardiva. Il messaggio (#rows interessate) è una cosa dello strumento client interpretata da SSMS ecc: tuttavia c'è un pacchetto inviato con queste informazioni. Certo, sono consapevole di come funziona @@ rowcount ecc., Ma non è questo il punto della domanda ...
gbn

1
Nessun problema. Personalmente concordo con il tuo punto di vista; Stavo solo commentando che non esiste una correlazione diretta tra i risultati di un costrutto IF / WHERE EXISTS e SET NOCOUNT. Ottengo risultati coerenti da quei costrutti indipendentemente da NOCOUNT. Se hai qualcosa che dice il contrario, ti preghiamo di inviarlo a modo mio.
Jeremy S,

1
@Jeremy Seghi: hai ragione: SET NOCOUNT ON elimina solo il pacchetto aggiuntivo di dati al client. SE, @@ ROWCOUNT ecc. Non sono interessati. Oh, e rompe SQLDataAdapters ... :-)
gbn

1
@Kieren Johnstone: col senno di poi, è una domanda scarsamente formulata. Vorrei votare per chiudere se questa non fosse la mia domanda ...
gbn

Risposte:


246

Ok ora ho fatto le mie ricerche, ecco l'affare:

Nel protocollo TDS, SET NOCOUNT ONsalva solo 9 byte per query mentre il testo "SET NOCOUNT ON" stesso è di ben 14 byte. Pensavo che 123 row(s) affectedfosse restituito dal server in testo normale in un pacchetto di rete separato, ma non è così. In realtà è una piccola struttura chiamata DONE_IN_PROCincorporata nella risposta. Non è un pacchetto di rete separato, quindi non vengono sprecati viaggi di andata e ritorno.

Penso che si possa attenersi al comportamento di conteggio predefinito quasi sempre senza preoccuparsi delle prestazioni. In alcuni casi, tuttavia, il calcolo anticipato del numero di righe influisce sulle prestazioni, ad esempio un cursore di sola andata. In tal caso, NOCOUNT potrebbe essere una necessità. A parte questo, non è assolutamente necessario seguire il motto "usa NOCOUNT ove possibile".

Ecco un'analisi molto dettagliata sull'insignificanza SET NOCOUNTdell'impostazione: http://daleburnett.com/2014/01/everything-ever-wanted-know-set-nocount/


Infatti. Sto usando SET NOCOUNT ON da sempre, ma marc_s ha sottolineato la limitazione di SQLDataAdapter nell'altra domanda.
gbn,

Grazie. I byte o le dimensioni non sono il problema per me, ma il client deve elaborarlo. È la dipendenza SQLDataAdapter che mi stupisce comunque ...
gbn

2
Grazie per la tua risposta. Accetterò questo a causa delle tue indagini, che hanno innescato ulteriori informazioni e lavoro da parte mia. Non sono d'accordo sul sovraccarico però: può importare come mostrano altre risposte. Saluti, gbn
gbn

13
Non è il numero di byte il suo ritardo di andata e ritorno sul filo che è il killer delle prestazioni
racingsnail

1
Nel flusso di messaggi TDS, e l'esempio è quando si inseriscono solo valori nella tabella. DONINPROCIl messaggio (RPC) o DONE(BATCH) viene trasmesso in streaming con rowcountimpostato su righe interessate, mentre done_countflag è true, indipendentemente dal fatto che lo NO_COUNTsia ON. Dipende dall'implementazione della libreria client nei casi in cui la query contiene istruzioni SELECT o chiamate RPC che selezionano, potrebbe essere necessario disabilitare il conteggio ... QUANDO disabilitato, le righe vengono comunque conteggiate per l'istruzione select, ma il flag DONE_COUNTè impostato su false. Leggi sempre ciò che suggerisce la tua lib client poiché interpreterà lo stream token (message) invece di te
Milan Jaric

87

Mi ci sono voluti un sacco di ricerche per trovare cifre di riferimento reali intorno a NOCOUNT, quindi ho pensato di condividere un breve riassunto.

  • Se la procedura memorizzata utilizza un cursore per eseguire molte operazioni molto rapide senza risultati restituiti, la disattivazione di NOCOUNT può richiedere circa 10 volte il tempo di averlo attivato. 1 Questo è lo scenario peggiore.
  • Se la procedura memorizzata esegue solo una singola operazione rapida senza risultati restituiti, l'impostazione di NOCOUNT ON potrebbe produrre un aumento delle prestazioni di circa il 3%. 2 Ciò sarebbe coerente con una tipica procedura di inserimento o aggiornamento. (Vedi i commenti su questa risposta per alcune discussioni sul perché questo potrebbe non essere sempre più veloce.)
  • Se la procedura memorizzata restituisce risultati (ovvero SELEZIONA qualcosa), la differenza di prestazioni diminuirà proporzionalmente alla dimensione del set di risultati.

5
+1 per l'impatto sul cursore, questo è coerente con le mie osservazioni
zvolkov,

Il punto 2 non è preciso! Intendo il blog a cui si riferisce. Non è mai stato! DONE e DONEPROC e DONEINPROC vengono inviati con le stesse dimensioni indipendentemente dal fatto che NO_COUNT sia impostato su ON o OFF. RowCount è ancora lì come ULONGLONG (64 byte) e il flag DONE_COUNT è ancora lì ma il valore del bit è 0. Il server SQL conterà comunque il numero di righe, anche se non sei interessato a leggere il valore dal token DONE. Se leggi @@ ROWCOUNT hai aggiunto più byte al flusso di token sotto forma di token returnvalue o come altro colmetadata + token di riga!
Milan Jaric,

@MilanJaric: grazie per averlo chiamato. Mi hai aiutato a capire che avevo collegato l'articolo sbagliato. Il collegamento è ora aggiornato e l'articolo fa un argomento convincente per mostrare che può esserci un leggero miglioramento delle prestazioni con SET NOCOUNT ON. Pensi che ci siano problemi con i metodi di riferimento utilizzati?
StriplingWarrior

:) ancora impreciso su SET NOCOUNT OFF / ON, L'errore è che il secondo SP non ha SET NOCOUNT OFF;ed è per questo che pensano di non ottenere byte extra in risposta. Un benchmark preciso dovrebbe essere usato SET NOCOUNT ONnella SET NOCOUNT OFFprocedura memorizzata a sinistra e a destra. In questo modo otterrai il pacchetto TDS con DONEINPROC (SET NOCOUNT ...), di nuovo dieci DONEINPROC (INSERT statement), e poi RETURNVALUE(@@ROWCOUNT), poi RETURNSTATUS 0per sp e finaly DONPROC. L'errore è presente perché il secondo sp non ha SET NOCOUNT OFF nel corpo!
Milan Jaric,

Per riformulare ciò che hanno trovato ma non si sono resi conto è che se si dispone di 1K richiesta di cursore di recupero, innanzitutto effettuare una richiesta per impostare NOCOUNT su ON o OFF per la connessione, quindi utilizzare la stessa connessione per chiamare il cursore di recupero 1K volte per risparmiare un po 'di larghezza di banda. Lo stato di connessione effettivo per NOCOUNT ON o OFF non influirà sulla larghezza di banda, potrebbe semplicemente confondere la lib client ad es. ADO.net o ODBC. Quindi "non usare SET NOCOUNT <WHATEVER> se ti interessa la larghezza di banda" :)
Milan Jaric

77
  • Quando SET NOCOUNT è ON, il conteggio (che indica il numero di righe interessate da un'istruzione Transact-SQL) non viene restituito. Quando SET NOCOUNT è OFF, il conteggio viene restituito. Viene utilizzato con qualsiasi istruzione SELECT, INSERT, UPDATE, DELETE.

  • L'impostazione di SET NOCOUNT è impostata in fase di esecuzione o di esecuzione e non in fase di analisi.

  • SET NOCOUNT ON migliora le prestazioni della stored procedure (SP).

  • Sintassi: SET NOCOUNT {ON | OFF}

Esempio di SET NOCOUNT ON:

inserisci qui la descrizione dell'immagine

Esempio di SET NOCOUNT OFF:

inserisci qui la descrizione dell'immagine


7
Facile e veloce da capire con schermate. Ottimo lavoro. :)
shaijut

35

Immagino che sia un problema DBA vs. sviluppatore.

Per lo più da dev, direi di non usarlo a meno che non sia assolutamente necessario, perché usarlo può violare il codice ADO.NET (come documentato da Microsoft).

E immagino che come DBA, saresti più dall'altra parte: usalo quando possibile a meno che tu non debba davvero impedirne l'uso.

Inoltre, se i tuoi sviluppatori usano mai "RecordsAffected" restituito dalla ExecuteNonQuerychiamata del metodo di ADO.NET , sei nei guai se tutti lo usano SET NOCOUNT ONpoiché in questo caso, ExecuteNonQuery restituirà sempre 0.

Vedi anche il post sul blog di Peter Bromberg e controlla la sua posizione.

Quindi si riduce davvero a chi arriva a stabilire gli standard :-)

Marc


È interessato al semplice CRUD: la griglia di dati che menziona potrebbe usare xml per inviare più righe per evitare viaggi di andata e ritorno ecc.
gbn

Immagino che se non usi mai SqlDataAdapters e non controlli mai e fai affidamento sul numero "record interessati" restituito da ExecuteNonQuery (ad esempio se usi qualcosa come Linq-to-SQL o NHibernate), allora probabilmente non hai problemi utilizzando SET NOCOUNT ON in tutti i processi memorizzati.
marc_s,

12

Se stai dicendo che potresti avere anche client diversi, ci sono problemi con ADO classico se SET NOCOUNT non è impostato su ON.

Uno che sperimento regolarmente: se una procedura memorizzata esegue un numero di istruzioni (e quindi vengono restituiti un numero di messaggi "xxx righe interessate"), ADO sembra non gestirlo e genera l'errore "Impossibile modificare la proprietà ActiveConnection di un oggetto Recordset che ha un oggetto Command come sorgente. "

Quindi in genere consiglio di impostarlo su ON a meno che non ci sia davvero un buon motivo per non farlo. potresti aver trovato l'ottimo motivo per cui devo andare a leggere di più.


9

A rischio di complicare le cose, incoraggio una regola leggermente diversa da tutte quelle che vedo sopra:

  • Impostare sempre NOCOUNT ONnella parte superiore di un proc, prima di eseguire qualsiasi lavoro nel proc, ma anche sempre di SET NOCOUNT OFFnuovo, prima di restituire qualsiasi recordset dal proc memorizzato.

Quindi "generalmente continua con nocount, tranne quando stai effettivamente restituendo un set di risultati". Non so in alcun modo che questo possa violare qualsiasi codice client, significa che il codice client non ha mai bisogno di sapere nulla sui proc interni e non è particolarmente oneroso.


Grazie. È possibile ottenere il conteggio delle righe dal DataSet o dal contenitore di consumo ovviamente, ma potrebbe essere utile. Non possiamo avere trigger su SELECT, quindi sarebbe sicuro: la maggior parte degli errori del client sono causati da messaggi spuri sulle modifiche dei dati.
gbn

Il problema con questa regola è che è più difficile testarlo rispetto a "SET NOCOUNT ON nella parte superiore del proc?"; Mi chiedo se gli strumenti di analisi SQL come SQL Enlight possano testare questo genere di cose ... Aggiungendolo alla mia lista di cose da fare a lungo termine per il mio progetto di formattatore SQL :)
Tao

5

Per quanto riguarda i fattori scatenanti della rottura di NHibernate, ho avuto l'esperienza di prima mano. Fondamentalmente, quando NH fa un AGGIORNAMENTO si aspetta un certo numero di righe interessate. Aggiungendo SET NOCOUNT ON ai trigger si ottiene il numero di righe su ciò che NH si aspettava, risolvendo così il problema. Quindi sì, consiglio vivamente di disattivarlo per i trigger se si utilizza NH.

Per quanto riguarda l'utilizzo negli SP, è una questione di preferenze personali. Avevo sempre disattivato il conteggio delle righe, ma, di nuovo, non ci sono argomenti concreti in nessun modo.

In una nota diversa, dovresti davvero considerare di abbandonare l'architettura basata su SP, quindi non avrai nemmeno questa domanda.


1
Non sono d'accordo con l'allontanamento dai proc memorizzati. Ciò significherebbe che dobbiamo avere lo stesso SQL in 2 basi di codice client diverse e fidarci dei nostri programmatori client. Siamo DBA per sviluppatori. E non intendi "SET NOCOUNT ON "?
gbn,

@CodeBlend: basta Google per più di quanto tu abbia mai bisogno. Tuttavia ... stackoverflow.com/a/4040466/27535
gbn

3

Volevo verificare che "SET NOCOUNT ON" non salvi un pacchetto di rete né un roundtrip

Ho usato un SQLServer di prova 2017 su un altro host (ho usato una macchina virtuale) 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 Quindi ho tracciato i pacchetti sulla porta 1433 con lo strumento 'Wireshark': pulsante 'filtro cattura' -> 'porta 1433'

exec procNoCount

questo è il pacchetto di risposta: 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

questo è il pacchetto di risposta: 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

Nella riga 40 posso vedere '07' che è il numero di 'righe interessate'. È incluso nel pacchetto di risposta. Nessun pacchetto aggiuntivo.

Dispone tuttavia di 13 byte extra che potrebbero essere salvati, ma probabilmente non ne vale la pena rispetto alla riduzione dei nomi di colonna (ad es. "ManagingDepartment" in "MD")

Quindi non vedo alcun motivo per usarlo per le prestazioni

MA Come altri hanno già detto, può rompere ADO.NET e ho anche inciampato su un problema usando Python: MSSQL2008 - Pyodbc - SQL precedente non era una query

Quindi probabilmente una buona abitudine ancora ...


1
SET NOCOUNT ON;

Questa riga di codice viene utilizzata in SQL per non restituire il numero di righe interessate nell'esecuzione della query. Se non richiediamo il numero di righe interessate, possiamo utilizzarlo in quanto ciò aiuterebbe a risparmiare l'utilizzo della memoria e aumenterebbe l'intervallo di esecuzione della query.


2
Si noti che @@ ROWCOUNT è ancora impostato. SET NOCOUNT ON elimina qualsiasi risposta aggiuntiva che SQL Server invia al client. Vedi la risposta accettata sopra per favore
gbn

1

SET NOCOUNT ON; Il codice precedente interromperà il messaggio generato dal motore del server sql alla finestra dei risultati con il fronte dopo l'esecuzione del comando DML / DDL.

Perché lo facciamo? Poiché il motore del server SQL richiede alcune risorse per ottenere lo stato e generare il messaggio, viene considerato come sovraccarico del motore del server SQL.


1

Un posto che SET NOCOUNT ONpuò davvero aiutare è dove stai facendo query in un ciclo o un cursore. Questo può aggiungere molto traffico di rete.

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

L'attivazione delle statistiche del client in SSMS, una serie di EXEC NoCountOne EXEC NoCountOffmostra che c'era un traffico extra di 390 KB su NoCountOff:

statistiche del cliente

Probabilmente non è l'ideale per fare query in un ciclo o cursore, ma non viviamo nemmeno nel mondo ideale :)


0

So che è una domanda piuttosto vecchia. ma solo per l'aggiornamento.

Il modo migliore per usare "SET NOCOUNT ON" è metterlo come prima istruzione nel tuo SP e impostarlo nuovamente su OFF appena prima dell'ultima istruzione SELECT.


0

SET NOCOUNT ON consente anche di accedere alle righe interessate in questo modo:

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

risultati

affectedRows

1

messaggi

Comandi completati correttamente.

Tempo di completamento: 2020-06-18T16: 20: 16.9686874 + 02: 00


-1

Non so come testare SET NOCOUNT ON tra client e SQL, quindi ho testato un comportamento simile per altri comandi SET "SET TRANSACTION ISOLATION LEVEL READ UNCIMMITTED"

Ho inviato un comando dalla mia connessione modificando il comportamento predefinito di SQL (LEGGI COMMITTATO) ed è stato modificato per i comandi successivi. Quando ho modificato il livello ISOLATION all'interno di una procedura memorizzata, non è cambiato il comportamento della connessione per il comando successivo.

Conclusione attuale,

  1. La modifica delle impostazioni all'interno della procedura memorizzata non modifica le impostazioni predefinite della connessione.
  2. La modifica delle impostazioni inviando comandi mediante ADOCOnnection modifica il comportamento predefinito.

Penso che questo sia rilevante per altri comandi SET come "SET NOCOUNT ON"


Il precedente punto 1 implica che non è necessario IMPOSTARE NOCOUNT alla fine perché non influisce sull'ambiente globale?
funkymushroom

Non sono sicuro se questo è ciò che intendeva con il punto 1, ma nei miei test sì, apparentemente l'ambiente globale non è influenzato da SET NOCOUNT ON all'interno di una procedura memorizzata.
Doug,

Questa è stata una scelta sbagliata di confronto, perché il Livello di isolamento è esplicitamente correlato a una particolare transazione, quindi non c'è motivo particolare di aspettarsi che sia coerente con un'impostazione comeNOCOUNT
IMSoP

-1

if (imposta no count == off)

{allora manterrà i dati di quanti record interessati, quindi riduci le prestazioni} altrimenti {non traccerà il record delle modifiche, quindi migliora perfomace}}


-1

A volte anche le cose più semplici possono fare la differenza. Uno di questi semplici elementi che dovrebbero far parte di ogni procedura memorizzata è SET NOCOUNT ON. Questa riga di codice, inserita all'inizio di una procedura memorizzata, disattiva i messaggi che SQL Server restituisce al client dopo l'esecuzione di ogni istruzione T-SQL. Questa operazione viene eseguita per tutti SELECT, INSERT, UPDATE, e DELETEle dichiarazioni. Avere queste informazioni è utile quando si esegue un'istruzione T-SQL in una finestra di query, ma quando vengono eseguite le procedure memorizzate non è necessario che queste informazioni vengano restituite al client.

Rimuovendo questo sovraccarico aggiuntivo dalla rete, è possibile migliorare notevolmente le prestazioni complessive per il database e l'applicazione.

Se è ancora necessario ottenere il numero di righe interessate dall'istruzione T-SQL in esecuzione, è comunque possibile utilizzare l' @@ROWCOUNTopzione. Emettendo una SET NOCOUNT ONfunzione this ( @@ROWCOUNT) funziona ancora e può ancora essere utilizzato nelle procedure memorizzate per identificare quante righe sono state interessate dall'istruzione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.