GO Nach jeder T-SQL-Anweisung

34

Was ist der Grund für die Verwendung der GO-Anweisung nach jeder SQL-Anweisung? Ich verstehe, dass GO das Ende des Batch signalisiert und / oder die Reputation von Anweisungen zulässt, aber welchen Vorteil es hat, wenn es nach jeder Anweisung verwendet wird.

Ich bin nur neugierig, da viele Microsoft-Dokumentationen usw. sie nach jeder Anweisung verwenden, oder ich habe gerade erst angefangen, es zu bemerken.

Was gilt auch als Best Practice?

Der Idiot
quelle

Antworten:

51

Vor der Beantwortung der Frage, wann und warum sie verwendet werden soll, ist es entscheidend, genau zu verstehen, was GOist und was nicht.

Das Schlüsselwort GOwird von SQL Server Management Studio und SQLCMD verwendet, um nur eines zu kennzeichnen: das Ende eines Anweisungsstapels. In der Tat können Sie sogar ändern, was Sie zum Beenden von Stapeln verwenden, um etwas anderes als "GO":

Bildbeschreibung hier eingeben

Der obige Screenshot ist eine konfigurierbare Option in SSMS.

Aber was ist eine Charge? Diese BOL-Referenz sagt es am besten:

Ein Batch ist eine Gruppe von mindestens einer Transact-SQL-Anweisung , die zur Ausführung gleichzeitig von einer Anwendung an SQL Server gesendet wird.

So einfach ist das. Es ist nur eine benutzerdefinierte Methode, mit der eine Anwendung (ja ... eine Anwendung) Anweisungen an SQL Server sendet. Schauen wir uns ein Beispiel dafür an. Ich verwende PowerShell, um nachzuahmen, wie eine Anwendung Anweisungen und Stapel an SQL Server sendet:

$ConnectionString = "data source = SomeSQLInstance; initial catalog = AdventureWorks2012; trusted_connection = true; application name = BatchTesting;"

try {
    $SqlConnection = New-Object System.Data.SqlClient.SqlConnection($ConnectionString)
    $SqlCmd = New-Object System.Data.SqlClient.SqlCommand
    $SqlCmd.Connection = $SqlConnection

    # first batch of statements
    #
    $SqlCmd.CommandText = "
        select * from humanresources.department where departmentid = 1;
        select * from humanresources.department where departmentid = 2;
        select * from humanresources.department where departmentid = 3;
        select * from humanresources.department where departmentid = 4;"

    # execute the first batch
    #
    $SqlConnection.Open()
    $SqlCmd.ExecuteNonQuery()
    $SqlConnection.Close()

    # second batch of statements
    #
    $SqlCmd.CommandText = "
        select * from humanresources.department where departmentid = 5;
        select * from humanresources.department where departmentid = 6;
        select * from humanresources.department where departmentid = 7;
        select * from humanresources.department where departmentid = 8;"

    # execute the second batch
    #
    $SqlConnection.Open()
    $SqlCmd.ExecuteNonQuery()
    $SqlConnection.Close()
}
catch {
    $SqlCmd.Dispose()
    $SqlConnection.Dispose()
    Write-Error $_.Exception
}

Die Kommentare verraten es, aber Sie können oben sehen, dass wir programmgesteuert zwei Stapel an SQL Server senden . Lassen Sie uns das jedoch überprüfen. Ich wähle hier Extended Events:

create event session BatchTesting
on server
add event sqlserver.sql_batch_starting
(
    set
        collect_batch_text = 1
    where
    (
        sqlserver.client_app_name = N'BatchTesting'
    )
),
add event sqlserver.sql_batch_completed
(
    set
        collect_batch_text = 1
    where
    (
        sqlserver.client_app_name = N'BatchTesting'
    )
),
add event sqlserver.sql_statement_starting
(
    set
        collect_statement = 1
    where
    (
        sqlserver.client_app_name = N'BatchTesting'
    )
),
add event sqlserver.sql_statement_completed
(
    set
        collect_statement = 1
    where
    (
        sqlserver.client_app_name = N'BatchTesting'
    )
)
add target package0.event_file
(
    set
        filename = N'<MyXelLocation>\BatchTesting.xel'
);
go

alter event session BatchTesting
on server
state = start;
go

All dies XEvents Sitzung macht , ist die Anweisungen und Chargen erfasst , die und vollständig von einer Anwendung mit dem Namen starten "BatchTesting"(wenn Sie meine Verbindungszeichenfolge in meinem Powershell - Codebeispiel bemerken, ist es eine schnelle Möglichkeit , mit Hilfe der „Anwendung an einem bestimmten Urheber der Ereignisse zu sehen name "Verbindungsstringparameter und Filterung davon).

Nachdem ich den PowerShell-Code zum Senden dieser Stapel und Anweisungen ausgeführt habe, werden die folgenden Ergebnisse angezeigt:

Bildbeschreibung hier eingeben

Wie Sie auf dem Screenshot sehen können, ist es klar, wie die Anweisungen in zwei verschiedene Stapel unterteilt sind. Dies wird auch durch die Mittel deutlich, mit denen wir die Stapel aufgerufen haben. Und wenn wir uns batch_textdas erste Vorkommen von ansehen sql_batch_starting, sehen wir alle Anweisungen, die in diesem Batch enthalten sind:

    select * from humanresources.department where departmentid = 1;
    select * from humanresources.department where departmentid = 2;
    select * from humanresources.department where departmentid = 3;
    select * from humanresources.department where departmentid = 4;

Mit dieser Erklärung, was ein Stapel ist, erhalten Sie jetzt die Antwort auf Ihre Frage, wann Stapel zu beenden sind. Die Regeln für Chargen finden Sie in dieser BOL-Referenz für Chargen :

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 CREATE-Anweisung muss den Batch 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. Anschließend werden die neuen Spalten im selben Stapel referenziert.

Wenn eine EXECUTE-Anweisung die erste Anweisung in einem Stapel ist, ist das EXECUTE-Schlüsselwort nicht erforderlich. Das Schlüsselwort EXECUTE ist erforderlich, wenn die EXECUTE-Anweisung nicht die erste Anweisung im Stapel ist.

Ebenso können bestimmte Laufzeitfehler (bei Kompilierungsfehlern kann die Ausführung eines Stapels nicht gestartet werden), die während eines Stapels auftreten, unterschiedliche Verhaltensweisen hervorrufen: den Stapel vollständig abzubrechen oder den Stapel fortzusetzen und nur die fehlerhafte Anweisung abzubrechen (siehe oben) link gibt zwei wirklich gute Beispiele: Ein arithmetischer Überlauffehler bricht beispielsweise die Ausführung des Stapels ab, während ein Fehler bei einer Einschränkungsverletzung nur den Abschluss der aktuellen Anweisung verhindert, der Stapel jedoch weiterhin ausgeführt wird.

Wie viele Dinge in unserem Beruf wird jedoch die persönliche Präferenz eine große Triebfeder dafür sein, wie Sie als Einzelperson und Verfasser von T-SQL-Code Batches beenden. Einige Leute nur explizit Chargen definieren , wenn sie absolut haben (siehe oben für diese Anforderungen) und andere beenden Chargen programmatisch 100% der Zeit , auch wenn sie nur eine einzige Anweisung in einem Abfragefenster in SSMS ausführen. Die meisten Menschen fallen normalerweise irgendwo in die Mitte dieser beiden Grenzen. Anweisungsbeendiger haben, was es wert ist, die gleiche Anhängerschaft mit auch sehr wenigen erzwungenen Anforderungen. Ein großer Teil von all dem ist , Code - Stil , wo es nicht erzwungen wird (in SSMS und SQLCMD).

Thomas Stringer
quelle
Vielleicht ein naiver Kommentar, aber es fällt mir auf, dass SQL Server bestimmt haben könnte, was in Stapeln ausgeführt werden soll (genauso wie viele andere Optimierungen vom Datenbankmodul verarbeitet werden). Verwenden Sie beispielsweise die von Ihnen beschriebenen Regeln, anstatt sich auf den Benutzer zu verlassen, um sie zu skripten. Dies kann fehleranfällig sein und scheint die Skripte unnötig aufzublähen.
Steve Chambers
1
@SteveChambers mein Gefühl genau. Die Antwort lautet "So einfach ist das" (Ein Batch ist eine Gruppe von mindestens einer Transact-SQL-Anweisung, die zur Ausführung gleichzeitig von einer Anwendung an SQL Server gesendet wird.) Dies ist jedoch nicht der Fall. Es gibt Kombinationen von Anweisungen, bei denen ich versuchen könnte, einen fehlgeschlagenen Stapel einzusenden. Letztendlich denke ich, dass Sie verstehen müssen, warum und wie sich das Senden eines Stapels vom Senden einer Reihe einzelner Anweisungen unterscheidet - daher habe ich schließlich meine eigene Antwort zu dieser Anweisung beigetragen: stackoverflow.com/a/56370223/3714936 - was auch auf Ihren Kommentar zutrifft .
youcantryreachingme