Sql-Server

GO 在每個 T-SQL 語句之後

  • April 2, 2014

在每個 SQL 語句之後使用 GO 語句的原因是什麼?我知道 GO 表示批處理的結束和/或允許語句的聲譽,但是在每個語句之後使用它有什麼優勢。

我只是好奇,因為很多 Microsoft 文件等在每個聲明之後都開始使用它,或者我剛剛開始注意到。

還有什麼被認為是最佳實踐?

在回答何時使用它以及為什麼使用它之前,首先要準確了解什麼GO是什麼,什麼不是。

SQL Server Management Studio 和 SQLCMD 使用該關鍵字GO來表示一件事且只有一件事:一批語句的結束。事實上,您甚至可以將用於終止批處理的內容更改為“GO”以外的內容:

在此處輸入圖像描述

上面的螢幕截圖是 SSMS 中的一個可配置選項。

但是什麼是批次?? 這個 BOL 參考說得最好:

批處理是一組同時從應用程序發送到 SQL Server 以執行的一個或多個 Transact-SQL 語句。

就那麼簡單。這只是應用程序(是的……應用程序)向 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
}

註釋給出了它,但您可以在上面看到我們以程式方式將兩批發送到 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 程式碼以發送這些批處理和語句後,我看到以下結果:

在此處輸入圖像描述

正如您從螢幕截圖中看到的那樣,很清楚語句是如何劃分為兩個不同的批次的,我們用來呼叫批次的方式也很明顯。如果我們查看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;

隨著對批次是什麼的解釋,現在可以回答您何時終止批次的問題。批次規則可在有關批次的 BOL 參考中找到:

CREATE DEFAULT、CREATE FUNCTION、CREATE PROCEDURE、CREATE RULE、CREATE SCHEMA、CREATE TRIGGER 和 CREATE VIEW 語句不能與批處理中的其他語句組合。CREATE 語句必須啟動批處理。該批次後面的所有其他語句將被解釋為第一個 CREATE 語句定義的一部分。

不能更改表,然後在同一批次中引用新列。

如果 EXECUTE 語句是批處理中的第一個語句,則不需要 EXECUTE 關鍵字。如果 EXECUTE 語句不是批處理中的第一個語句,則需要 EXECUTE 關鍵字。

同樣,在批處理期間發生的某些執行時錯誤(編譯錯誤不允許開始執行批處理)可能會導致不同的行為:完全中止批處理,或繼續批處理並僅中止有問題的語句(上述連結給出了兩個非常好的例子:例如,算術溢出錯誤將停止批處理的執行,而約束違反錯誤只會阻止目前語句完成但批處理將繼續執行)。

然而,就像我們職業中的許多事情一樣,個人偏好將成為您作為個人和 T-SQL 程式碼編寫者如何終止批處理的巨大驅動力。有些人只在絕對必要時才顯式定義批處理(有關這些要求,請參見上文),而其他人 100% 的時間以程式方式終止批處理,即使他們只在 SSMS 的查詢視窗中執行單個語句。大多數人通常落在這兩個邊界的中間。就其價值而言,語句終止符具有相同的追隨者,而且強制要求也很少。所有這一切的很大一部分是程式碼樣式,它沒有被強制執行(在 SSMS 和 SQLCMD 中)。

引用自:https://dba.stackexchange.com/questions/59975