我在SQL Server GO
is considered a batch separator中知道这一点。
我的问题是:,有批次分隔符的意义是什么?,它给你带来了什么好处,你为什么要使用它?
示例:我经常在SQL代码中看到它的使用,如下所示,我不明白为什么它会被认为是最佳实践。据我所知,如果没有所有的GO
语句,代码将是相同的:
USE AdventureWorks2012;
GO
BEGIN TRANSACTION;
GO
IF @@TRANCOUNT = 0
BEGIN
SELECT FirstName, MiddleName
FROM Person.Person WHERE LastName = 'Adams';
ROLLBACK TRANSACTION;
PRINT N'Rolling back the transaction two times would cause an error.';
END;
ROLLBACK TRANSACTION;
PRINT N'Rolled back the transaction.';
GO
(来源:technet documentation):
发布于 2013-12-21 04:22:02
在这个例子中,它没有任何用处。
但是,批处理中必须只有许多语句。
例如CREATE PROCEDURE
。
此外,通常在进行模式更改(例如,向现有表中添加新列)之后,必须在不同的批处理中单独编译使用新模式的语句。
通常,提交由GO
分隔的单独批处理的另一种方法是使用EXEC
在子批处理中执行SQL
发布于 2013-12-21 05:08:45
作为TechNet says,GO
向SQL实用程序表示SQL批处理的结束。例如,当SQL Server Management Studio遇到批处理分隔符时,它知道到目前为止的所有文本都是一个独立的SQL查询。
我们在我们的软件中使用了类似的技术。我们将所有的过程、模式脚本、数据转换等都保存在SQL脚本文件中(签入到源代码控制中)。当我们的安装程序读取其中一个脚本文件时,GO告诉我们的解析器“你可以运行你已经读过的SQL”。
像GO
这样的批处理分隔符的一个很好的特性是,您可以在同一脚本中包含两个通常会导致错误的SQL查询。例如,尝试删除并在同一脚本文件中重新创建同一存储过程:
if exists (select * from sys.procedures where name = 'sp_test')
drop procedure sp_test
create procedure sp_test as
begin
select 1
end
如果你运行上面的代码,你会得到一个错误:
消息156,级别15,状态1,过程sp_test,第5行关键字'begin‘附近的语法不正确。
SSMS将向您显示错误:
语法不正确。“'CREATE”必须是批处理中的唯一语句。
使用批次分隔符可以帮助您解决此错误:
if exists (select * from sys.procedures where name = 'sp_test')
drop procedure sp_test
GO
create procedure sp_test as
begin
select 1
end
例如,如果您希望源代码控制中的单个SQL脚本维护存储过程或函数,这将非常方便。我们经常使用这个模式。
您可以做的另一件有趣的事情是使用它来多次运行查询:
INSERT INTO MyTable (...) ...
GO 10 -- run all the above 10 times!
正如the answers to this SO question演示的那样,您还可以将其配置为您想要的任何内容。如果你想惹恼你的同事,把批次分隔符设置成类似于"WHERE“而不是"GO”。有趣!:)
发布于 2019-05-30 08:39:46
有批次分隔符的意义是什么?
在阅读了许多答案并发表了评论后,以下是我的想法。
真正的问题是“拥有批处理的意义是什么?”
批处理有两个含义,go
的另一个用法可能会很有用:
1.将批处理中的所有语句编译为一个执行计划
作为一名SQL开发人员,我不知道这对您有什么影响。但事实就是如此。这意味着您不能在同一批处理中包含一些语句。例如,您不能先ALTER
表以添加列,然后在同一批处理中select
该列-因为在编译执行计划时,该列不存在以供选择。
我认为,对于SQL Server是否应该能够在不要求开发人员在其脚本中包含go
语句的情况下自行检测到这一点,存在一个开放的争论。此外,文档还说ODBC connection可能永远不会发出go
命令。我不清楚如果包含刚才给出的ALTER
/ SELECT
示例,通过ODBC运行的脚本会有什么行为。
2.本地声明的变量仅存在于它们被声明为的批处理范围内
这两点结合在一起有点糟糕。我有一个创建和更改DB结构(表、过程等)的脚本,我想在脚本的开头声明变量,这些变量将用于管理整个脚本的行为。只要我需要包装一个批处理(例如,由于一条ALTER
语句-请参见上面的观点1 ),这些“配置”变量就会超出作用域,并且不能在脚本中进一步使用。我的解决方法是创建一个表,将配置变量持久化到表中,然后通过我的脚本一直从该表中读取,然后在最后删除该表(以防其他人遇到这种情况)。
第二个含义实际上可以用于优势-如果你的脚本正在做大量的工作,而你只是想清除所有的局部变量,你可以简单地包括一个GO
语句,然后声明新的变量(即.并重新使用相同的名称,如果这是您想要的)。
3. GO有一个可选参数(名为"count"),它告诉服务器将批处理操作重复多次
这种用法似乎是添加到GO
语句中的很好的附加功能。我认为GO
的初始或主要功能更多地与编译单个执行计划有关,如第一点所述-否则关键字可能类似于REPEAT 10
-但重复什么?批次。如果不使用GO
表示批处理,则重复命令只能重复前面的单个语句。因此,GO
是重复批处理的好方法。
参考
所有这些都来自于对MS documentation on GO的理解。许多其他的答案-这里和其他问题-都是针对文档的片段,但我认为文档本身无法真正解释为什么批处理有好处-因此我对一个已经得到很好评论的问题做出了贡献。
附录
写完上面的内容后,我确实在GO
文档中找到了微软提到的Rules for Using Batches。该链接页面说明执行计划由多个语句组成。它还说,可以将单个语句重新编译为新的执行计划(即由SQL Server自动处理批处理)。因此,例如,在CREATE TABLE
语句之后,您可能有一个到该表的INSERT
。在前面的语句中创建表之后,将重新编译该INSERT
语句。
这再次强化了这样一种想法,即SQL Server可能会检测到表的ALTER
后面跟着SELECT
的情况,并且它需要重新编译SELECT
(请参见上面的第1点),如果使用ODBC,可能就会发生这种情况(请参见上面的第1点)。
这些新信息都不会改变上面给出的3点。我刚才给出的链接包含额外的阅读内容,并以“规则”结尾,它们是:
https://stackoverflow.com/questions/20711326
复制相似问题