Inspiriert von dieser Frage, wo es unterschiedliche Ansichten zu SET NOCOUNT gibt ...
Sollten wir SET NOCOUNT ON für SQL Server verwenden? Wenn nicht, warum nicht?
Was es macht Edit 6, am 22. Juli 2011
Es unterdrückt die Meldung "xx Zeilen betroffen" nach jeder DML. Dies ist eine Ergebnismenge, die der Client beim Senden verarbeiten muss. Es ist winzig, aber messbar (siehe Antworten unten)
Bei Triggern usw. erhält der Client mehrere "betroffene xx Zeilen", was bei einigen ORMs, MS Access, JPA usw. zu allen möglichen Fehlern führt (siehe Änderungen unten).
Hintergrund:
Allgemein anerkannte Best Practice (ich dachte bis zu dieser Frage) ist die Verwendung SET NOCOUNT ON
in Triggern und gespeicherten Prozeduren in SQL Server. Wir verwenden es überall und ein kurzer Blick auf Google zeigt, dass auch viele SQL Server-MVPs zustimmen.
MSDN sagt, dass dies einen .net SQLDataAdapter beschädigen kann .
Für mich bedeutet dies, dass der SQLDataAdapter auf die einfache CRUD-Verarbeitung beschränkt ist, da erwartet wird, dass die Nachricht "n betroffene Zeilen" übereinstimmt. Also kann ich nicht verwenden:
- WENN EXISTIERT, um Duplikate zu vermeiden (keine Zeilen betroffene Nachricht) Hinweis: Mit Vorsicht verwenden
- WO NICHT EXISTIERT (weniger Zeilen als erwartet
- Filtern Sie triviale Updates heraus (z. B. ändern sich keine Daten tatsächlich)
- Führen Sie vorher einen Tabellenzugriff durch (z. B. Protokollierung).
- Komplexität oder Denormierung verbergen
- usw
In der Frage sagt marc_s (wer kennt sich mit SQL aus), benutze es nicht. Dies unterscheidet sich von dem, was ich denke (und ich betrachte mich auch als etwas kompetent in SQL).
Es ist möglich, dass mir etwas fehlt (zögern Sie nicht, auf das Offensichtliche hinzuweisen), aber was denken Sie da draußen?
Hinweis: Es ist Jahre her, seit ich diesen Fehler gesehen habe, weil ich SQLDataAdapter heutzutage nicht mehr verwende.
Änderungen nach Kommentaren und Fragen:
Edit: Mehr Gedanken ...
Wir haben mehrere Clients: Einer kann einen C # SQLDataAdaptor verwenden, ein anderer kann nHibernate von Java verwenden. Diese können mit auf unterschiedliche Weise beeinflusst werden SET NOCOUNT ON
.
Wenn Sie gespeicherte Prozesse als Methoden betrachten, ist es eine schlechte Form (Anti-Pattern) anzunehmen, dass einige interne Verarbeitungen für Ihre eigenen Zwecke auf eine bestimmte Weise funktionieren.
Edit 2: Ein Trigger, der die nHibernate-Frage bricht , wo SET NOCOUNT ON
nicht gesetzt werden kann
(und nein, es ist kein Duplikat davon )
Edit 3: Noch mehr Infos, danke an meinen MVP-Kollegen
- KB 240882 , Problem, das bei SQL 2000 und früheren Versionen zu Verbindungsabbrüchen führt
- Demo des Leistungsgewinns
Bearbeiten 4: 13 Mai 2011
Bricht Linq 2 SQL auch, wenn nicht angegeben?
Bearbeiten 5: 14 Jun 2011
Bricht JPA ab, gespeicherter Prozess mit Tabellenvariablen: Unterstützt JPA 2.0 SQL Server-Tabellenvariablen?
Bearbeiten 6: 15 Aug 2011
Das SSMS-Datenraster "Zeilen bearbeiten" erfordert SET NOCOUNT ON: Trigger mit GROUP BY aktualisieren
Bearbeiten 7: 07 Mar 2013
Ausführlichere Details von @RemusRusanu: Macht SET NOCOUNT ON wirklich einen so großen Leistungsunterschied aus?
Antworten:
Ok, jetzt habe ich meine Nachforschungen angestellt. Hier ist der Deal:
Im TDS-Protokoll werden
SET NOCOUNT ON
nur 9 Bytes pro Abfrage gespeichert, während der Text "SET NOCOUNT ON" selbst satte 14 Bytes umfasst. Früher dachte ich, dass dies123 row(s) affected
vom Server im Klartext in einem separaten Netzwerkpaket zurückgegeben wurde, aber das ist nicht der Fall. Es ist in der Tat eine kleine Struktur namensDONE_IN_PROC
eingebettet in die Antwort. Es ist kein separates Netzwerkpaket, sodass keine Hin- und Rückflüge verschwendet werden.Ich denke, Sie können sich fast immer an das Standardzählverhalten halten, ohne sich um die Leistung sorgen zu müssen. Es gibt jedoch einige Fälle, in denen die Berechnung der Anzahl der Zeilen im Voraus die Leistung beeinträchtigen würde, z. B. ein Nur-Vorwärts-Cursor. In diesem Fall könnte NOCOUNT eine Notwendigkeit sein. Abgesehen davon besteht absolut keine Notwendigkeit, dem Motto "NOCOUNT wo immer möglich verwenden" zu folgen.
Hier ist eine sehr detaillierte Analyse über die Bedeutungslosigkeit der
SET NOCOUNT
Einstellung: http://daleburnett.com/2014/01/everything-ever-wanted-know-set-nocount/quelle
DONINPROC
(RPC) - oderDONE
(BATCH) -Nachricht wird gestreamt, wobeirowcount
auf betroffene Zeilen gesetzt wird, währenddone_count
Flag isttrue
, unabhängig davon, ob dies der FallNO_COUNT
istON
. Abhängig von der Implementierung der Client-Bibliothek in Fällen, in denen die Abfrage SELECT-Anweisungen oder RPC-Aufrufe enthält, die auswählen, muss möglicherweise die Zählung deaktiviert werden. WENN deaktiviert, werden die Zeilen für die select-Anweisung weiterhin gezählt, das FlagDONE_COUNT
wird jedoch auf gesetztfalse
. Lesen Sie immer, was Ihre Client-Bibliothek vorschlägt, da sie den Token- (Nachrichten-) Stream anstelle von Ihnen interpretiertIch musste viel graben, um echte Benchmark-Zahlen rund um NOCOUNT zu finden, also dachte ich mir, ich würde eine kurze Zusammenfassung teilen.
quelle
SET NOCOUNT OFF;
und deshalb denken sie, dass sie keine zusätzlichen Bytes als Antwort erhalten. Ein genauer Benchmark wäre die VerwendungSET NOCOUNT ON
in derSET NOCOUNT OFF
gespeicherten Prozedur links und rechts. Auf diese Weise erhalten Sie das TDS-Paket mitDONEINPROC (SET NOCOUNT ...)
, wieder zehnDONEINPROC (INSERT statement)
und dannRETURNVALUE(@@ROWCOUNT)
, dannRETURNSTATUS 0
für sp und schließlichDONPROC
. Der Fehler liegt vor, weil der zweite SP im Körper kein SET NOCOUNT OFF hat!Wenn SET NOCOUNT auf ON gesetzt ist, wird die Anzahl (die die Anzahl der von einer Transact-SQL-Anweisung betroffenen Zeilen angibt) nicht zurückgegeben. Wenn SET NOCOUNT AUS ist, wird die Zählung zurückgegeben. Es wird mit jeder Anweisung SELECT, INSERT, UPDATE, DELETE verwendet.
Die Einstellung von SET NOCOUNT wird zur Ausführungs- oder Laufzeit und nicht zur Analysezeit festgelegt.
SET NOCOUNT ON verbessert die Leistung der gespeicherten Prozedur (SP).
Syntax: SET NOCOUNT {ON | AUS }
Beispiel für SET NOCOUNT ON:
Beispiel für SET NOCOUNT OFF:
quelle
Ich denke, bis zu einem gewissen Grad handelt es sich um ein Problem zwischen DBA und Entwickler.
Meistens würde ich als Entwickler sagen, dass Sie es nur verwenden, wenn Sie es unbedingt müssen - da die Verwendung Ihren ADO.NET-Code beschädigen kann (wie von Microsoft dokumentiert).
Und ich denke, als DBA wären Sie eher auf der anderen Seite - verwenden Sie es, wann immer es möglich ist, es sei denn, Sie müssen die Verwendung wirklich verhindern.
Wenn Ihre Entwickler jemals "RecordsAffected" verwenden, das vom
ExecuteNonQuery
Methodenaufruf von ADO.NET zurückgegeben wird, sind Sie in Schwierigkeiten, wenn alle verwenden,SET NOCOUNT ON
da ExecuteNonQuery in diesem Fall immer 0 zurückgibt.Sehen Sie sich auch den Blog-Beitrag von Peter Bromberg an und überprüfen Sie seine Position.
Es kommt also wirklich darauf an, wer die Standards setzen darf :-)
Marc
quelle
Wenn Sie sagen, dass Sie möglicherweise auch andere Clients haben, gibt es Probleme mit klassischem ADO, wenn SET NOCOUNT nicht aktiviert ist.
Eine, die ich regelmäßig erlebe: Wenn eine gespeicherte Prozedur eine Reihe von Anweisungen ausführt (und daher eine Reihe von Nachrichten "xxx Zeilen betroffen" zurückgegeben werden), scheint ADO dies nicht zu behandeln und löst den Fehler "Die ActiveConnection-Eigenschaft eines Recordset-Objekts kann nicht geändert werden welches ein Befehlsobjekt als Quelle hat. "
Daher empfehle ich generell, es einzuschalten, es sei denn, es gibt einen wirklich guten Grund, dies nicht zu tun. Sie haben vielleicht den wirklich sehr guten Grund gefunden, in den ich mehr hineinlesen muss.
quelle
Auf die Gefahr hin, die Dinge komplizierter zu machen, empfehle ich eine etwas andere Regel als alle oben genannten:
NOCOUNT ON
oben in einem Prozess, bevor Sie Arbeiten im Prozess ausführen, aber auch immerSET NOCOUNT OFF
wieder, bevor Sie Datensätze aus dem gespeicherten Prozess zurückgeben.Also "im Allgemeinen nicht zählen, außer wenn Sie tatsächlich eine Ergebnismenge zurückgeben". Ich kenne keine Möglichkeiten, wie dies einen Client-Code beschädigen kann. Dies bedeutet, dass der Client-Code nie etwas über die Proc-Interna wissen muss und nicht besonders belastend ist.
quelle
In Bezug auf die Auslöser, die NHibernate brechen, hatte ich diese Erfahrung aus erster Hand. Grundsätzlich erwartet NH bei einem UPDATE eine bestimmte Anzahl betroffener Zeilen. Durch Hinzufügen von SET NOCOUNT ON zu den Triggern erhalten Sie die Anzahl der Zeilen wieder auf den erwarteten Wert von NH, wodurch das Problem behoben wird. Also ja, ich würde definitiv empfehlen, es für Trigger auszuschalten, wenn Sie NH verwenden.
In Bezug auf die Verwendung in SPs ist es eine Frage der persönlichen Präferenz. Ich hatte die Zeilenanzahl immer ausgeschaltet, aber andererseits gibt es auch keine wirklich starken Argumente.
In einem anderen Sinne sollten Sie wirklich überlegen, sich von der SP-basierten Architektur zu entfernen, dann werden Sie diese Frage nicht einmal haben.
quelle
Ich wollte mich vergewissern, dass 'SET NOCOUNT ON' weder ein Netzwerkpaket noch eine Hin- und Rückfahrt speichert
Ich habe einen Test-SQLServer 2017 auf einem anderen Host verwendet (ich habe eine VM verwendet).
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
Dann habe ich Pakete auf Port 1433 mit dem Tool 'Wireshark' verfolgt: Schaltfläche 'Filter erfassen' -> 'Port 1433'exec procNoCount
Dies ist das Antwortpaket:
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
Dies ist das Antwortpaket:
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
In Zeile 40 sehe ich '07', was die Anzahl der 'betroffenen Zeile (n)' ist. Es ist im Antwortpaket enthalten. Kein zusätzliches Paket.
Es hat jedoch 13 zusätzliche Bytes, die gespeichert werden könnten, aber wahrscheinlich nicht mehr wert sind, als Spaltennamen zu reduzieren (z. B. 'ManagingDepartment' auf 'MD').
Ich sehe also keinen Grund, es für die Leistung zu verwenden
ABER Wie andere bereits erwähnt haben, kann ADO.NET beschädigt werden, und ich bin auch auf ein Problem mit Python gestoßen : MSSQL2008 - Pyodbc - Vorheriges SQL war keine Abfrage
Also wahrscheinlich noch eine gute Angewohnheit ...
quelle
Diese Codezeile wird in SQL verwendet, um die bei der Ausführung der Abfrage betroffenen Zahlenzeilen nicht zurückzugeben. Wenn wir die Anzahl der betroffenen Zeilen nicht benötigen, können wir dies verwenden, da dies zur Speicherung der Speichernutzung und zur Erhöhung der Ausführungsgeschwindigkeit der Abfrage beitragen würde.
quelle
SET NOCOUNT ON; Der obige Code stoppt die von der SQL Server Engine generierte Nachricht im Fronted-Ergebnisfenster nach der Ausführung des DML / DDL-Befehls.
Warum machen wir das? Da die SQL Server-Engine einige Ressourcen benötigt, um den Status abzurufen und die Nachricht zu generieren, wird dies als Überlastung der SQL Server-Engine angesehen. Daher setzen wir die Nicht-Zähl-Nachricht auf.
quelle
Ein Ort, der
SET NOCOUNT ON
wirklich helfen kann, ist, wo Sie Abfragen in einer Schleife oder einem Cursor ausführen. Dies kann zu viel Netzwerkverkehr führen.Wenn Sie die Client-Statistik in SSMS aktivieren, wird ausgeführt
EXEC NoCountOn
undEXEC NoCountOff
zeigt, dass auf dem NoCountOff ein zusätzlicher 390-KB-Datenverkehr vorhanden war:Wahrscheinlich nicht ideal, um Abfragen in einer Schleife oder einem Cursor durchzuführen, aber wir leben auch nicht in einer idealen Welt :)
quelle
Ich weiß, dass es eine ziemlich alte Frage ist. aber nur zum aktualisieren.
Die beste Möglichkeit, "SET NOCOUNT ON" zu verwenden, besteht darin, es als erste Anweisung in Ihrem SP zu platzieren und es kurz vor der letzten SELECT-Anweisung wieder auszuschalten.
quelle
Ich weiß nicht, wie ich SET NOCOUNT ON zwischen Client und SQL testen soll, daher habe ich ein ähnliches Verhalten für andere SET-Befehle getestet: "SET TRANSACTION ISOLATION LEVEL READ UNCIMMITTED"
Ich habe einen Befehl von meiner Verbindung gesendet, der das Standardverhalten von SQL (READ COMMITTED) geändert hat, und er wurde für die nächsten Befehle geändert. Als ich die ISOLATION-Ebene in einer gespeicherten Prozedur geändert habe, hat sich das Verbindungsverhalten für den nächsten Befehl nicht geändert.
Aktuelle Schlussfolgerung,
Ich denke, dass dies für andere SET-Befehle wie "SET NOCOUNT ON" relevant ist.
quelle
NOCOUNT
if (setze keine Zählung == aus)
{Dann werden Daten darüber gespeichert, wie viele Datensätze betroffen sind, um die Leistung zu verringern.} Sonst {Es werden keine Änderungen aufgezeichnet, wodurch die Leistung verbessert wird.}}
quelle
Manchmal können sogar die einfachsten Dinge einen Unterschied machen. Eines dieser einfachen Elemente, das Teil jeder gespeicherten Prozedur sein sollte, ist
SET NOCOUNT ON
. Diese eine Codezeile am Anfang einer gespeicherten Prozedur deaktiviert die Nachrichten, die SQL Server nach Ausführung jeder T-SQL-Anweisung an den Client zurücksendet. Dies erfolgt für alleSELECT
,INSERT
,UPDATE
, undDELETE
Aussagen. Diese Informationen sind praktisch, wenn Sie eine T-SQL-Anweisung in einem Abfragefenster ausführen. Wenn jedoch gespeicherte Prozeduren ausgeführt werden, müssen diese Informationen nicht an den Client zurückgegeben werden.Durch Entfernen dieses zusätzlichen Overheads aus dem Netzwerk kann die Gesamtleistung Ihrer Datenbank und Anwendung erheblich verbessert werden.
Wenn Sie weiterhin die Anzahl der Zeilen abrufen müssen, die von der ausgeführten T-SQL-Anweisung betroffen sind, können Sie die
@@ROWCOUNT
Option weiterhin verwenden . Durch die Ausgabe einerSET NOCOUNT ON
Funktion funktioniert this (@@ROWCOUNT
) weiterhin und kann weiterhin in Ihren gespeicherten Prozeduren verwendet werden, um zu ermitteln, wie viele Zeilen von der Anweisung betroffen waren.quelle