web-dev-qa-db-ja.com

すべてのT-SQLステートメントの後のGO

すべてのSQLステートメントの後にGOステートメントを使用する理由は何ですか? GOがバッチの終了を通知し、ステートメントのレピュテーションを許可することを理解していますが、ステートメントごとにGOを使用するとどのような利点がありますか。

多くのMicrosoftのドキュメントなどがすべてのステートメントの後でそれを使い始めたので、またはおそらく気づき始めたので、私は興味があります。

また、ベストプラクティスとは何ですか。

34
TheIdiot

いつどのように使用するかとその理由を説明する前に、 GO が何であるか、および何でないかを正確に理解することが最初に重要です。

キーワードGOは、SQL Server Management StudioとSQLCMDによって、1つのことだけを表すために使用されます。ステートメントのバッチの終わりです。実際、バッチを「GO」以外に終了するために使用するものを変更することもできます。

enter image description here

上記のスクリーンショットは、構成可能なSSMS内のオプションです。

しかし、バッチとは何ですか? このBOL参照 はそれを最もよく言います:

バッチは1つ以上のTransact-SQLステートメントのグループで、アプリケーションからSQL Serverに同時に送信されて実行されます。

そのような単純な。これは、アプリケーション(はい...アプリケーション)がSQL Serverにステートメントを送信するカスタム方法にすぎません。このアプリケーションのような例を見てみましょう。 PowerShellを使用して、SQL Serverにステートメントとバッチを送信するためのアプリケーションの動作を模倣します。

$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
}

コメントはそれを提供しますが、プログラムで2つのbatchesをプログラムでSQL Serverに送信していることがわかります。それを確認しましょう。ここでの私の選択は、拡張イベントを使用することです。

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

このXEventsセッションが実行しているのは、"BatchTesting"という名前のアプリケーションから開始して完了するステートメントとバッチをキャプチャすることだけです(PowerShellコードの例で接続文字列に気付いた場合は、イベントの特定の発生元をすばやく確認できます) 「アプリケーション名」の接続文字列パラメータを使用し、それをフィルタリングすることにより)。

PowerShellコードを実行してこれらのバッチとステートメントを送信すると、次の結果が表示されます。

enter image description here

スクリーンショットからわかるように、ステートメントが2つの異なるバッチにどのように分割されているかは明らかです。これは、バッチの呼び出しに使用した方法からも明らかです。そして、batch_textの最初の出現のsql_batch_startingを調べると、そのバッチに含まれているすべてのステートメントを確認できます。

    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;

whatのバッチの説明により、whenバッチを終了します。バッチのルールは バッチに関するこのBOLリファレンス にあります。

CREATE DEFAULT、CREATE FUNCTION、CREATE PROCEDURE、CREATE RULE、CREATE SCHEMA、CREATE TRIGGER、およびCREATE VIEWステートメントは、バッチ内の他のステートメントと組み合わせることはできません。 CREATEステートメントはバッチを開始する必要があります。そのバッチで続く他のすべてのステートメントは、最初のCREATEステートメントの定義の一部として解釈されます。

テーブルを変更してから、同じバッチで参照される新しい列を変更することはできません。

EXECUTEステートメントがバッチの最初のステートメントである場合、EXECUTEキーワードは不要です。 EXECUTEステートメントがバッチ内の最初のステートメントでない場合は、EXECUTEキーワードが必要です。

同様に、バッチ中に発生する特定のランタイムエラー(コンパイルエラーではバッチの実行を開始できません)は、異なる動作を引き起こす可能性があります:バッチを完全に中止する、またはバッチを続行して問題のステートメントのみを中止する(上記)リンクは2つの本当に良い例を示します。たとえば、算術オーバーフローエラーはバッチの実行を停止しますが、制約違反エラーは現在のステートメントの完了を妨げるだけで、バッチは実行を続けます)。

しかし、私たちの専門職の多くのことと同様に、T-SQLコードの個人および作成者がバッチを終了する方法の背後には、個人的な好みが大きな原動力になります。一部の人は、絶対にバッチを明示的に定義するだけですする必要がある(これらの要件については上記を参照)、その他の人は、バッチをプログラムで終了しますSSMSのクエリウィンドウで単一のステートメントのみを実行している場合でも、100%の時間。ほとんどの人は通常、これら2つの境界の真ん中のどこかに落ちます。価値があるのは、ステートメントターミネーターのフォローが同じで、強制される要件がほとんどないことです。このすべての大部分はコードスタイルであり、強制されません(SSMSおよびSQLCMDで)。

51
Thomas Stringer