SQL Server:什么是批处理语句(即使用“GO”)有用?

时间:2013-12-20 20:19:07

标签: sql-server tsql

我知道在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):

4 个答案:

答案 0 :(得分:35)

在这个例子中,没有任何用处。

然而,许多陈述必须是批次中的唯一陈述。

例如CREATE PROCEDURE

通常,在进行架构更改(例如,向现有表添加新列)之后,必须使用新架构单独编译语句。

通常,提交由GO分隔的单独批次的替代方法是使用EXEC

在子批处理中执行SQL

答案 1 :(得分:27)

作为TechNet saysGO它表示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关键字。