Ich weiß, dass in SQL Server GO
ein Batch-Trennzeichen betrachtet wird .
Meine Frage ist: Was bringt ein Batch-Separator? Welchen Nutzen bringt es Ihnen und warum möchten Sie es nutzen?
Beispiel: Ich habe oft gesehen, dass es im SQL-Code wie folgt verwendet wird, und ich kann nicht verstehen, warum es als Best Practice angesehen wird. Soweit ich das beurteilen kann, wäre der Code ohne alle GO
Aussagen gleich:
USE AdventureWorks2012;
GO
BEGIN TRANSACTION;
GO
IF @@TRANCOUNT = 0
BEGIN
SELECT FirstName, MiddleName
FROM Person.Person WHERE LastName = 'Adams';
ROLLBACK TRANSACTION;
PRINT N'Rolling back the transaction two times would cause an error.';
END;
ROLLBACK TRANSACTION;
PRINT N'Rolled back the transaction.';
GO
(Quelle: Technet-Dokumentation ):
sql-server
tsql
Zain Rizvi
quelle
quelle
Antworten:
In dem dortigen Beispiel nützt es überhaupt nichts.
Viele Anweisungen müssen jedoch die einzigen im Stapel sein.
Wie zum Beispiel
CREATE PROCEDURE
.Auch häufig müssen nach dem Vornehmen von Schemaänderungen (z. B. Hinzufügen einer neuen Spalte zu einer vorhandenen Tabelle) Anweisungen, die das neue Schema verwenden, separat in einem anderen Stapel kompiliert werden.
Im Allgemeinen besteht eine Alternative zum Senden separater
GO
Stapel, die durch getrennt sind, darin, die SQL in einem untergeordneten Stapel mit auszuführenEXEC
quelle
CREATE TABLE T(X INT);SELECT * FROM T
funktioniert einwandfrei, da dieSELECT
Kompilierung verzögert wird. Aber dann, nachdem die Tabelle erstellt wurde,ALTER TABLE T ADD Y INT;SELECT Y FROM T
würde mit einem ungültigen Spaltennamenfehler fehlschlagen, da diese Anweisung nicht kompiliert kompiliert wird.Wie TechNet sagt ,
GO
bedeutet dies für die SQL-Dienstprogramme das Ende eines SQL-Stapels. Wenn SQL Server Management Studio beispielsweise auf das Batch-Trennzeichen stößt, weiß es, dass der gesamte bisherige Text eine unabhängige SQL-Abfrage ist.Wir verwenden eine ähnliche Technik in unserer Software. Wir speichern alle unsere Prozesse, Schemaskripte, Datenkonvertierungen usw. in SQL-Skriptdateien (eingecheckt in die Quellcodeverwaltung). Wenn unser Installationsprogramm eine dieser Skriptdateien liest, teilt GO unserem Parser mit, dass Sie die bereits gelesene SQL ausführen können.
Das Schöne an einem Batch-Trennzeichen
GO
ist, dass Sie zwei SQL-Abfragen in dasselbe Skript aufnehmen können, die normalerweise einen Fehler verursachen würden. Versuchen Sie beispielsweise, dieselbe gespeicherte Prozedur in derselben Skriptdatei zu löschen und neu zu erstellen:if exists (select * from sys.procedures where name = 'sp_test') drop procedure sp_test create procedure sp_test as begin select 1 end
Wenn Sie den obigen Code ausführen, wird eine Fehlermeldung angezeigt:
Und SSMS zeigt Ihnen den Fehler:
Die Verwendung eines Batch-Separators kann Ihnen dabei helfen, diesen Fehler zu umgehen:
if exists (select * from sys.procedures where name = 'sp_test') drop procedure sp_test GO create procedure sp_test as begin select 1 end
Dies ist sehr praktisch, wenn Sie beispielsweise möchten, dass ein einzelnes SQL-Skript in der Quellcodeverwaltung eine gespeicherte Prozedur oder Funktion verwaltet. Wir verwenden dieses Muster häufig.
Eine weitere interessante Möglichkeit besteht darin, eine Abfrage mehrmals auszuführen:
INSERT INTO MyTable (...) ... GO 10 -- run all the above 10 times!
Wie die Antworten auf diese SO-Frage zeigen, können Sie sie auch nach Ihren Wünschen konfigurieren. Wenn Sie sich mit Ihren Mitarbeitern anlegen möchten, setzen Sie das Batch-Trennzeichen auf "WHERE" anstelle von "GO". Spaß! :) :)
quelle
go 10
ist in der Tat nützlich - abergo
in Ihrem früheren Beispiel nicht zwingend erforderlich.go
hängt vom Verständnis der Auswirkungen des Stapelns ab - in erster Linie, dass ein einzelner Ausführungsplan aus dem gesamten Stapel erstellt wird. Also entschied ich mich schließlich, meine eigene Antwort beizutragen, um zu versuchen, das "Warum" zu erklären - siehe unten, hier: stackoverflow.com/a/56370223/3714936Nachdem ich viele der Antworten gelesen und zu Kommentaren beigetragen habe, denke ich Folgendes.
Die eigentliche Frage lautet: "Was bringt es, eine Charge zu haben?"
Es gibt zwei Implikationen der Stapelverarbeitung, die eine gewisse Bedeutung haben, und es gibt eine zusätzliche Verwendung von
go
, die nützlich sein kann:1. Alle Anweisungen in einem Stapel werden in einem einzigen Ausführungsplan zusammengefasst
Wie sich dies auf Sie als SQL-Entwickler auswirkt, weiß ich nicht. Aber da ist es. Dies hat zur Folge, dass Sie einige Anweisungen nicht im selben Stapel haben können . Beispielsweise können Sie in
ALTER
einer Tabelle keine Spalte hinzufügen, dannselect
diese Spalte im selben Stapel - weil erstellen, da diese Spalte beim Kompilieren des Ausführungsplans nicht zur Auswahl vorhanden ist.Ich denke, es gibt ein offenes Argument dafür, ob SQL Server dies selbst erkennen kann, ohne dass Entwickler
go
Anweisungen in ihre Skripte aufnehmen müssen. Darüber hinaus heißt es in den Dokumenten, dass ODBC-Verbindungen möglicherweise niemals einengo
Befehl ausgeben . Mir ist nicht klar, wie sich ein über ODBC ausgeführtes Skript verhalten würde, wenn es das gerade angegebeneALTER
/ -Beispiel enthalten würdeSELECT
.2. Lokal deklarierte Variablen existieren nur im Rahmen des Stapels, in dem sie deklariert wurden
Diese beiden Punkte zusammen saugen irgendwie. Ich habe ein Skript, das DB-Strukturen (Tabellen, Prozeduren usw.) erstellt und ändert, und ich möchte zu Beginn des Skripts Variablen deklarieren, die zur Steuerung des Verhaltens des Skripts insgesamt verwendet werden. Sobald ich eine Charge einpacken muss (z. B. aufgrund einer
ALTER
Anweisung - siehe Punkt 1 oben), fallen diese "Konfigurations" -Variablen aus dem Gültigkeitsbereich und können nicht weiter unten im Skript verwendet werden. Meine Problemumgehung besteht darin, eine Tabelle zu erstellen, die Konfigurationsvariablen in der Tabelle beizubehalten, sie dann vollständig durch mein Skript zu lesen und die Tabelle am Ende zu löschen (falls jemand anderes damit konfrontiert ist).Diese zweite Implikation kann tatsächlich zum Vorteil genutzt werden. Wenn Ihr Skript viel Arbeit leistet und Sie einfach alle Ihre lokalen Variablen löschen möchten, können Sie einfach eine
GO
Anweisung einfügen und dann neue Variablen deklarieren (dh die wiederverwenden) gleiche Namen, wenn Sie das wollen).3. GO verfügt über einen optionalen Parameter (mit dem Namen "count"), der den Server anweist, die Stapelaktionen mehrmals zu wiederholen
Diese Verwendung scheint eine nette zusätzliche Funktionalität zu sein, die der
GO
Anweisung hinzugefügt wurde . Ich glaube, die anfängliche oder primäre Funktion vonGO
bezieht sich eher auf die Erstellung eines einzelnen Ausführungsplans, wie in Punkt 1 erwähnt - ansonsten könnte das Schlüsselwort auch so etwas wie seinREPEAT 10
- aber was wiederholen? Der Stapel. OhneGO
die Angabe eines Stapels konnte ein Wiederholungsbefehl immer nur die vorherige einzelne Anweisung wiederholen. DaherGO
ist eine gute Möglichkeit, Chargen zu wiederholen .Referenz
All dies ergibt sich aus dem Versuch, die MS-Dokumentation zu GO zu verstehen . Viele der anderen Antworten - hier und bei anderen Fragen - greifen Teile der Dokumentation auf, aber ich denke, die Dokumentation selbst erklärt nicht wirklich, warum das Stapeln überhaupt einen Vorteil hat - daher mein Beitrag zu einem bereits gut kommentierten Frage.
Nachtrag
Nachdem ich das oben Gesagte geschrieben hatte , fand ich die von Microsoft in der
GO
Dokumentation erwähnten Regeln für die Verwendung von Stapeln . Auf der verlinkten Seite wird erläutert, dass ein Ausführungsplan aus mehreren Anweisungen besteht. Es heißt auch, dass einzelne Anweisungen in einen neuen Ausführungsplan neu kompiliert werden können (dh von SQL Server, während der Stapel automatisch verarbeitet wird). Wenn Sie beispielsweise einer Anweisung folgen,CREATE TABLE
wird möglicherweise eineINSERT
in diese Tabelle aufgenommen. DieseINSERT
Anweisung wird neu kompiliert, nachdem die Tabelle in der vorherigen Anweisung erstellt wurde.Dies verstärkt die Idee, dass SQL Server wahrscheinlich jene Szenarien erkennen könnte, in denen
ALTER
auf eine Tabelle eine folgt,SELECT
und dass die Datei neu kompiliert werden mussSELECT
(siehe Punkt 1 oben), und möglicherweise passiert genau dies, wenn ODBC verwendet wird (siehe Punkt 1 oben).Keine dieser neuen Informationen ändert die 3 oben genannten Punkte. Der Link, den ich gerade gegeben habe, enthält zusätzliche Lektüre und endet mit "den Regeln", die diese sind:
Die Anweisungen CREATE DEFAULT, CREATE FUNCTION, CREATE PROCEDURE, CREATE RULE, CREATE SCHEMA, CREATE TRIGGER und CREATE VIEW können nicht mit anderen Anweisungen in einem Stapel kombiniert werden. Die Anweisung CREATE muss den Stapel starten. Alle anderen Anweisungen, die in diesem Stapel folgen, werden als Teil der Definition der ersten CREATE-Anweisung interpretiert.
Eine Tabelle kann nicht geändert werden, und dann werden die neuen Spalten im selben Stapel referenziert.
Wenn eine EXECUTE-Anweisung die erste Anweisung in einem Stapel ist, ist das Schlüsselwort EXECUTE nicht erforderlich. Das Schlüsselwort EXECUTE ist erforderlich, wenn die Anweisung EXECUTE nicht die erste Anweisung im Stapel ist.
quelle
Wie Martain sagte, müssen Anweisungen wie CREATE PROCEDURE die einzigen in einer Charge sein.
Beispielsweise verwende ich Stapeltrennzeichen, wenn ich gespeicherte Prozeduren erstelle und einem bestimmten Benutzer Berechtigungen hinzufüge. Wenn ich das "Los" weglassen würde, würde ich eine gespeicherte Prozedur erhalten, die bei jeder Ausführung Rechte gewährt. Auf diese Weise kann ich sie gleichzeitig schreiben und sicherstellen, dass ich keine gespeicherten Prozeduren schreibe, die beim Aufrufen brechen. Zum Beispiel
create procedure [procedurename] (parameters) as begin select prefname, lastname from people end go grant execute on [procedurename] to [username]
quelle