Database
 sql >> Database >  >> RDS >> Database

Sorprese e presupposti sulle prestazioni:IMPOSTARE NOCOUNT ON

Se hai mai utilizzato Management Studio, questo messaggio di output probabilmente ti sembrerà familiare:

(1 riga/i interessata/e)

Questo deriva da DONE_IN_PROC di SQL Server messaggio, che viene inviato al completamento con successo di qualsiasi istruzione SQL che ha restituito un risultato (incluso il recupero di un piano di esecuzione, motivo per cui vengono visualizzati due di questi messaggi quando in realtà è stata eseguita solo una singola query).

Puoi sopprimere questi messaggi con il seguente comando:

SET NOCOUNT ON;

Perché dovresti farlo? Perché questi messaggi sono chiacchieroni e spesso inutile . Nelle mie presentazioni sulle cattive abitudini e sulle migliori pratiche, parlo spesso dell'aggiunta di SET NOCOUNT ON; a tutte le stored procedure e attivandolo nel codice dell'applicazione che invia query ad hoc. (Durante il debug, tuttavia, potresti volere un flag per riattivare i messaggi, poiché l'output può essere utile in questi casi.)

Ho sempre aggiunto il disclaimer che il consiglio di attivare questa opzione ovunque non è universale; dipende. I recordset ADO della vecchia scuola li interpretavano effettivamente come set di risultati, quindi aggiungerli alle query dopo il fatto potrebbe effettivamente interrompere le applicazioni che li stanno già saltando manualmente. E alcuni ORM (tosse NHibernate tosse ) analizza effettivamente i risultati per determinare il successo dei comandi DML (ugh!). Verifica le modifiche.

So che a un certo punto avevo dimostrato a me stesso che questi messaggi loquaci potevano influire sulle prestazioni, specialmente su una rete lenta. Ma è passato molto tempo, e la scorsa settimana Erin Stellato mi ha chiesto se l'avessi mai documentato formalmente. Non l'ho fatto, quindi ecco qui. Faremo un ciclo molto semplice, in cui aggiorneremo una variabile di tabella un milione di volte:

SET NOCOUNT OFF;
 
DECLARE @i INT = 1;
DECLARE @x TABLE(a INT);
INSERT @x(a) VALUES(1);
 
SELECT SYSDATETIME();
 
WHILE @i < 1000000
BEGIN
  UPDATE @x SET a = 1;
  SET @i += 1;
END
 
SELECT SYSDATETIME();

Un paio di cose che potresti notare:

  • Il riquadro dei messaggi è invaso da istanze di (1 row(s) affected) Messaggio:

  • L'iniziale SELECT SYSDATETIME(); non si presenta nel riquadro dei risultati fino al completamento dell'intero batch. Ciò è dovuto all'allagamento.
  • L'esecuzione di questo batch ha richiesto circa 21 secondi.

Ora, ripetiamo questo senza il DONE_IN_PROC messaggi, modificando SET NOCOUNT OFF; a SET NOCOUNT ON; ed eseguilo di nuovo.

Sebbene il riquadro dei messaggi non fosse più invaso dalle righe interessate dai messaggi, l'esecuzione del batch ha comunque impiegato circa 21 secondi.

Poi ho pensato, aspetta un secondo, so cosa sta succedendo. Sono su una macchina locale, senza rete coinvolta, utilizzando la memoria condivisa, ho solo SSD e gocce e gocce di RAM...

Quindi ho ripetuto i test usando la mia copia locale di SSMS su un database SQL di Azure remoto:uno Standard, S0, V12. Questa volta, le query hanno richiesto molto più tempo, anche dopo aver ridotto le iterazioni da 1.000.000 a 100.000. Ma ancora una volta non c'era alcuna differenza tangibile nelle prestazioni se DONE_IN_PROC i messaggi venivano inviati o meno. Entrambi i batch hanno impiegato circa 104 secondi e questo è stato ripetibile per molte iterazioni.

Conclusione

Per anni ho operato con l'impressione che SET NOCOUNT ON; era una parte fondamentale di qualsiasi strategia di performance. Questo si basava su osservazioni che avevo fatto, probabilmente, in un'era diversa e che è meno probabile che si manifestino oggi.

Detto questo, continuerò a utilizzare SET NOCOUNT ON , anche se sull'hardware odierno non si notano differenze di prestazioni apprezzabili. Sono ancora convinto di ridurre al minimo il traffico di rete, ove possibile. Dovrei prendere in considerazione l'implementazione di un test in cui ho una larghezza di banda molto più limitata (forse qualcuno ha un CD AOL che può prestarmi?), o avere una macchina in cui la quantità di memoria è inferiore ai limiti del buffer di output di Management Studio, per essere sicuro che ci non è un potenziale impatto negli scenari peggiori. Nel frattempo, anche se potrebbe non modificare le prestazioni percepite della tua applicazione, potrebbe comunque aiutare il tuo portafoglio ad attivare sempre questa opzione impostata, specialmente in situazioni come Azure, dove potresti essere addebitato per il traffico in uscita.