在每个T-SQL语句之后执行


34

在每个SQL语句之后使用GO语句的背后原因是什么?我了解GO表示批处理已结束,并且/或者允许声明声誉,但是在每个声明之后使用它有什么优势。

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

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

Answers:


51

在回答何时使用它以及为什么使用之前,首先要弄清什么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
}

这些注释将其遗忘了,但是您可以在上面看到我们正在以编程方式将两个批处理发送到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代码编写者终止批处理方式的巨大推动力。有些人仅在绝对必要时才明确定义批处理(请参见上文中的那些要求),而其他人即使在SSMS的“查询窗口”中仅执行单个语句,也会以编程方式100%地终止批处理。大多数人通常落在这两个边界的中间。就其价值而言,语句终止符具有相同的追随者,并且执行需求也很少。所有这些的很大一部分是代码样式,在SSMS和SQLCMD中不强制使用。


也许只是幼稚的评论,但令我惊讶的是,SQL Server可以自行决定要批量运行的内容(与数据库引擎处理许多其他优化的方式相同)。例如,使用您描述的规则而不是依赖用户来编写脚本,这可能易于出错,并且似乎给脚本增加了不必要的膨胀。
史蒂夫·钱伯斯

1
@SteveChambers完全符合我的观点。答案说“就这么简单”(批处理是一组从一个应用程序同时发送到SQL Server以便执行的一个或多个Transact-SQL语句。)但事实并非如此。我可以尝试合并发送失败的语句。最后,我想你需要了解为什么如何发送批次比发送一组单独的语句的不同-所以我终于促成这一个我自己的答案:stackoverflow.com/a/56370223/3714936 -这还谈到了您的评论。
youcantryreachingme
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.