在每个 SQL 语句之后使用 GO 语句的原因是什么?我知道 GO 表示批处理的结束和/或允许语句的声誉,但是在每个语句之后使用它有什么优势。
我只是好奇,因为很多 Microsoft 文档等在每个声明之后都开始使用它,或者我刚刚开始注意到。
还有什么被认为是最佳实践?
在回答何时使用它以及为什么使用它之前,首先要准确了解什么GO是什么,什么不是。
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 代码示例中注意到我的连接字符串,这是一种使用“应用程序”来查看特定事件发起者的快速方法名称”连接字符串参数并过滤掉它)。
"BatchTesting"
在执行 PowerShell 代码以发送这些批处理和语句后,我看到以下结果:
正如您从屏幕截图中看到的那样,很清楚语句是如何划分为两个不同的批次的,我们用来调用批次的方式也很明显。如果我们查看batch_text第一次出现的sql_batch_starting,我们可以看到该批次中包含的所有语句:
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 关键字。
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 中)。