一尘不染

在每个 SQL 语句之后使用 GO 语句的原因是什么?

sql-server

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

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

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


阅读 160

收藏
2022-11-04

共1个答案

一尘不染

在回答何时使用它以及为什么使用它之前,首先要准确了解什么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 中)。

2022-11-04