我知道在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):
答案 0 :(得分:35)
在这个例子中,没有任何用处。
然而,许多陈述必须是批次中的唯一陈述。
例如CREATE PROCEDURE
。
通常,在进行架构更改(例如,向现有表添加新列)之后,必须使用新架构单独编译语句。
通常,提交由GO
分隔的单独批次的替代方法是使用EXEC
答案 1 :(得分:27)
作为TechNet says,GO
它表示SQL批处理对SQL实用程序的结束。例如,当SQL Server Management Studio遇到批处理分隔符时,它知道到目前为止所有文本都是一个独立的SQL查询。
我们在软件中使用了类似的技术。我们将所有的proc,模式脚本,数据转换等保存在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行语法不正确 靠近关键字'开始'。
SSMS会向您显示错误:
语法不正确。 '创建程序'必须是批次中唯一的陈述。
使用批处理分隔符可以帮助您解决此错误:
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"。有趣! :)
答案 2 :(得分:5)
就像马丁所说的那样,CREATE PROCEDURE这样的陈述必须是批量中唯一的。
例如,每当我创建存储过程并向某个用户添加权限时,我都会使用批处理分隔符。 如果我省略了'go',那么我最终会得到一个存储过程,每次运行时都会授予权限。通过这种方式,我可以同时编写它们,并确保在编写它们时我不会编写存储过程。例如
create procedure [procedurename]
(parameters)
as begin
select prefname, lastname from people
end
go
grant execute on [procedurename] to [username]
答案 3 :(得分:2)
拥有批处理分隔符有什么意义?
阅读了许多答案,并对评论做出了贡献,这就是我的想法。
真正的问题是“批量生产有什么意义?”
批处理有2个含义,它们具有一定的意义,另外还有go
的用法可能会有用:
1。一批中的所有语句都被编译成一个执行计划
这对您有何影响,作为SQL开发人员,我不知道。但是有。 这意味着您不能在同一批中包含某些语句。例如,您不能ALTER
在表中添加列,然后select
在同一批中添加该列-因为在编译执行计划时,该列不存在以供选择。
我认为,对于SQL Server是否应该能够在不要求开发人员在其脚本中包含go
语句的情况下自行检测到这一点,存在一个公开的争论。此外,文档说ODBC连接可能永远不会发出go
命令。对于我来说,尚不清楚如果脚本包含刚刚给出的ALTER
/ SELECT
示例,那么通过ODBC运行的脚本将如何表现。
2。本地声明的变量仅存在于声明它们的批处理范围内
这两点结合在一起很烂。我有一个用于创建和更改数据库结构(表,过程等)的脚本,我想在脚本的开头声明变量,这些变量将用于总体上控制脚本的行为。一旦我需要包装一个批处理(例如,由于ALTER
语句-参见上面的第1点),那些“ config”变量就超出了范围,无法在脚本。我的解决方法是创建一个表,将config变量持久保存到表中,然后从脚本中一直读取该表,然后将表放到最后(以防其他人面对该表)。
第二个含义实际上可以被利用-如果您的脚本正在做很多工作,而您只想清除所有局部变量,则可以只包含一个GO
语句,然后声明新变量(即,如果需要的话,并重复使用相同的名称)。
3。 GO有一个可选参数(名为“ count”),它告诉服务器多次重复执行批处理操作
此用法似乎是添加到GO
语句的不错的附加功能。我相信GO
的初始或主要功能更多地与单个执行计划的编译有关,如第1点所述-否则关键字也可能像REPEAT 10
一样-但重复什么?批次。如果没有GO
表示批处理,则repeat命令只能重复前面的单个语句。因此,GO
是重复批次的好方法。
参考
所有这些都来自于试图了解MS documentation on GO。许多其他答案-在这里以及其他问题上-都是文档的一部分,但我认为文档本身并不能真正解释为什么批处理首先有好处-因此,我对早已广受好评的所作的贡献问题。
附录
写完上面的内容之后,我确实在GO
文档中找到了Microsoft提到的Rules for Using Batches。链接的页面说明执行计划由多个语句组成。它还说,可以将单个语句重新编译为新的执行计划(即,通过SQL Server在自动处理批处理的同时)。因此,例如,在对CREATE TABLE
的语句之后,您可能在该表中有一个INSERT
。在先前的语句中创建表之后,将重新编译该INSERT
语句。
这强化了以下观点:SQL Server可能会检测到表中的ALTER
后跟SELECT
且需要重新编译SELECT
的那些情况。 (请参见上面的第1点),并且可能正是使用ODBC时发生的情况(请参见上述的第1点)。
此新信息均未更改上面给出的3点。我刚刚给出的链接包含其他内容,并以“规则”结尾,这些规则是:
CREATE DEFAULT,CREATE FUNCTION,CREATE PROCEDURE,CREATE RULE,CREATE SCHEMA,CREATE TRIGGER和CREATE VIEW语句不能与其他语句批量组合使用。 CREATE语句必须启动批处理。该批处理中的所有其他语句将被解释为第一个CREATE语句的定义的一部分。
不能更改表,然后不能在同一批中引用新列。
如果EXECUTE语句是批处理中的第一条语句,则不需要EXECUTE关键字。如果EXECUTE语句不是批处理中的第一条语句,则需要EXECUTE关键字。