GO 在每个 T-SQL 语句之后

The*_*iot 38 performance sql-server best-practices t-sql

在每个 SQL 语句之后使用 GO 语句的原因是什么?我知道 GO 表示批处理结束和/或允许声明的声誉,但是在每个声明之后使用它有什么好处。

我只是很好奇,因为很多 Microsoft 文档等都在每次声明后开始使用它,或者我才刚刚开始注意到。

还有什么被认为是最佳实践?

Tho*_*ger 56

在回答何时使用它以及为什么使用它之前,首先要准确了解什么GO是什么,什么不是。

GOSQL Server Management Studio 和 SQLCMD 使用该关键字来表示一件事并且只有一件事:一批语句的结束。事实上,您甚至可以将用于终止批处理的内容更改为“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
}
Run Code Online (Sandbox Code Playgroud)

注释泄露了它,但您可以在上面看到我们以编程方式向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
Run Code Online (Sandbox Code Playgroud)

这个 XEvents 会话所做的一切就是捕获从名为的应用程序开始和完成的语句和批处理"BatchTesting"(如果您注意到我的 PowerShell 代码示例中的连接字符串,这是一种通过使用“应用程序”来查看特定事件发起者的快速方法name”连接字符串参数并过滤掉它)。

在我执行 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;
Run Code Online (Sandbox Code Playgroud)

随着这种解释什么了一批是,现在来回答你的问题的时候来终止批次。有关批次的规则可在此 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 中)。