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

我很好奇,许多Microsoft文档等在每条语句之后都开始使用它,或者也许我刚刚开始注意到。

还被认为是最佳实践吗?

#1 楼

在回答何时使用它以及为什么使用它之前,首先要确切地了解GO是什么,什么不是。一件事,只有一件事:一批语句的结尾。实际上,您甚至可以将用于终止批处理的内容更改为“ GO”以外的内容:

但是什么是批次?此BOL参考最能说明问题:


批处理是一组从一个应用程序同时发送到SQL Server以便执行的一个或多个Transact-SQL语句。

就这么简单。这只是应用程序(是的,一个应用程序)将语句发送到SQL Server的自定义方式。让我们来看一个看起来像应用程序的例子。我将使用PowerShell模仿应用程序将语句和批处理发送到SQL Server的操作:

我们正在以编程方式将两个批处理发送到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
}


XEvents会话所做的所有工作都是捕获从名为GO的应用程序启动和完成的语句和批处理(如果您注意在我的PowerShell代码示例中的连接字符串,这是一种通过使用“应用程序名称”连接字符串参数并过滤掉该事件的特定发起者的快速方法。

执行后PowerShell代码发送那些批处理和语句,我看到以下结果:



从屏幕截图中可以看到,很明显,如何将语句分为两个不同的批处理,这也可以通过我们用来调用批处理的方式来看出。如果我们查看第一次出现的"BatchTesting"batch_text,我们可以看到该批次中包含的所有语句:

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

是的,现在是您何时终止批次问题的答案。在此BOL参考中可以找到有关批次的批次规则:语句不能与其他语句成批合并
。 CREATE语句必须开始
批处理。该批处理中随后的所有其他语句将被解释为第一个CREATE语句的定义的一部分。

无法更改表,然后在
同一批。

如果EXECUTE语句是批处理中的第一条语句,则不需要EXECUTE
关键字。如果
EXECUTE语句不是批处理中的第一条语句,则必须使用EXECUTE关键字。



同样,某些运行时错误(编译错误将不允许执行批处理期间发生的批处理可能会导致不同的行为:完全中止该批处理,或继续该批处理并仅中止有问题的语句(上面的链接给出了两个非常好的示例:例如,算术溢出错误将停止批处理的执行,而违反约束错误只会阻止当前语句完成,而批处理将继续执行。

但是,像我们行业中的许多事情一样,个人喜好将成为您作为个人和T-SQL代码编写者终止批处理方式的巨大推动力。有些人仅在绝对必要时才明确定义批处理(请参见上文中的那些要求),而其他人即使在SSMS的“查询窗口”中仅执行单个语句时,也会以编程方式100%地终止批处理。大多数人通常落在这两个边界的中间。就其价值而言,语句终止符具有相同的追随者,并且执行需求也很少。所有这些的很大一部分是代码样式,在SSMS和SQLCMD中不强制使用。

评论


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

–史蒂夫·钱伯斯(Steve Chambers)
19年5月3日,9:24



@SteveChambers完全符合我的观点。答案说“就这么简单”(批处理是一组从应用程序同时发送到SQL Server以便执行的一个或多个Transact-SQL语句。)但事实并非如此。我可以尝试合并发送失败的语句。最终,我认为您需要了解为什么发送批处理与发送一组单独的语句有何不同?-因此,我最终对此发表了自己的答案:stackoverflow.com/a/56370223/3714936-这也表达了您的意见。 。

–youcantryreachingme
19年5月30日,0:54