什么是“批次”,为什么要使用GO?


134

我已经阅读并阅读了MSDN等。好吧,所以它表明批处理已结束。

什么定义了批次?当我粘贴一堆脚本以同时全部运行时,我不明白为什么需要这样做。

我从不了解GO。任何人都可以更好地解释这一点,以及何时需要使用它(在进行几次或哪种类型的交易之后)?

例如,为什么在每次更新后我都需要GO:

 UPDATE [Country]
   SET [CountryCode] = 'IL'
 WHERE code = 'IL'

 GO

 UPDATE [Country]
   SET [CountryCode] = 'PT'
 WHERE code = 'PT'


FWIW,似乎a go也要重置/清除declare @foo变量声明-我得到的是您需要声明@foo错误,直到我注释掉了go
JL Peyret

Answers:


107

GO正确的一个TSQL命令。

相反,它是连接到SQL Server(Sybase或Microsoft的-不确定Oracle的功能)的特定客户端程序的命令,向客户端程序发信号,直到“执行”之前需要向其输入的命令集。发送到服务器执行。

为什么/何时需要它?

  • MS SQL Server中的GO具有“ count”参数-因此您可以将其用作“重复N次”快捷方式。

  • 极大的更新可能会填满SQL Server的日志。为避免这种情况,可能需要通过将它们分成较小的批次go

    在您的示例中,如果一组国家代码的更新量太大,将耗尽日志空间,则解决方案是将每个国家代码分隔为一个单独的交易-可以通过使用来在客户端上将它们分开来完成go

  • 为了工作,某些SQL语句必须由GO与以下语句分开。

    例如,至少在Sybase中,您不能删除表并在单个事务中重新创建同名表(创建过程/触发器的同上):

> drop table tempdb.guest.x1          
> create table tempdb.guest.x1 (a int)
> go
  Msg 2714, Level 16, State 1
  Server 'SYBDEV', Line 2
  There is already an object named 'x1' in the database.   
  
> drop table tempdb.guest.x1          
> go
> create table tempdb.guest.x1 (a int)
> go
>

4
GO语句不创建事务。如果您在一个BEGIN TRANSACTION语句中包含多个GO语句,最后您将执行ROLLBACK,它将回滚所有GO。并且如果在中间的一个GO中会出现一些错误,最后您将执行COMMIT,则将提交所有没有错误的GO。有点棘手。
TZ

7
GO不会“为您创建交易”。如果您未在显式事务中运行,则每个语句无论如何都会创建自己的事务。它是完全正交的。如果要将较大的更新拆分为较小的步骤,仍然可以像常规WHILE @@ROWCOUNT > 0模式一样在单个批处理中进行。
马丁·史密斯

3
如果您不是在显式事务中运行,那么无论如何UPDATE T1 SET X =2;UPDATE T1 SET X =2;它将作为两个单独的事务运行。的添加绝对没有区别。同样,如果您在显式事务运行,它将跨越多个批次,并且再次 没有区别。GOGO
马丁·史密斯

4
正如澄清任何以后阅读此书的人一样…… GO根本与事务无关,并使答案仅次于事务和日志文件的大小。 GO不会有任何效果。第一个和第三个答案是正确的。另外,有时您需要将语句分成不同的批处理,例如,您不能在表中添加一列,然后再在同一批处理中使用该列。(续)
罗伯特·麦基

4
此外,由于某些错误将使批处理中止(某些错误仅使语句中止),因此它在错误检测和恢复中也起作用。并且某些语句(CREATE VIEW,等)需要单独处理。
罗伯特·麦基

26

GO 不是声明,而是批处理分隔符。

GO客户端将分隔的块发送到服务器进行处理,客户端等待其结果。

例如,如果您写

DELETE FROM a
DELETE FROM b
DELETE FROM c

,这将作为单行3查询发送到服务器。

如果你写

DELETE FROM a
GO
DELETE FROM b
GO
DELETE FROM c

,这将作为3单行查询发送到服务器。

GO本身不会发送到服务器(无双关语)。这是一个纯客户端保留字,只能由SSMS和识别osql

如果您将使用自定义查询工具通过连接发送它,则服务器甚至不会识别它并发出错误。


4
为什么要全部批处理?
PositiveGuy 2010年

3
因此,GO意味着先发送它,然后再运行下一个批次,直到客户端收到“确定,该批次已完成并成功”,这基本上是GO所做的,以便下一个批次可以成功运行并且客户端知道确保批处理在服务器端完成之前。
PositiveGuy 2010年

3
@coffeeaddict:基本上是。此外,某些语句需要排在第一位(例如CREATE SCHEMA);其他要求是其批次中唯一的声明(例如SET SHOWPLAN_XML ON
Quassnoi 2010年

19

许多命令需要分批处理,例如 CREATE PROCEDURE

或者,如果您将列添加到表中,则该列应该是自己的批处理。如果您尝试在同一批次中选择新列,则它将失败,因为在解析/编译时该列不存在。

SQL工具使用GO来从一个脚本中解决此问题:它不是SQL关键字,因此引擎无法识别。

这是2个日常使用批次的具体示例。

编辑:在您的示例中,您不需要GO ...

编辑2,示例。您不能批量删除,创建和许可...特别重要的是,存储过程的结尾在哪里?

IF OBJECT_ID ('dbo.uspDoStuff') IS NOT NULL
    DROP PROCEDURE dbo.uspDoStuff
GO
CREATE PROCEDURE dbo.uspDoStuff
AS
SELECT Something From ATable
GO
GRANT EXECUTE ON dbo.uspDoStuff TO RoleSomeOne
GO

4

有时需要一遍又一遍地执行相同的命令或一组命令。这可能是为了插入或更新测试数据,也可能是对服务器进行性能测试的负载。进行此操作最简单的方法是,需要设置while循环并执行代码,但是在SQL 2005中,有一种更简单的方法可以执行此操作。

假设您要创建一个测试表并加载1000条记录。您可以发出以下命令,它将运行同一命令1000次:

CREATE TABLE dbo.TEST (ID INT IDENTITY (1,1), ROWID uniqueidentifier)
GO
INSERT INTO dbo.TEST (ROWID) VALUES (NEWID()) 
GO 1000

来源:http//www.mssqltips.com/tip.asp?tip = 1216

除此之外,它还标志着SQL块的“结束”(例如在存储过程中)...意味着您再次处于“干净”状态... eG:重置代码之前语句中使用的参数(不再定义)


好的,那你为什么需要GO。这样您就知道该表是在插入语句运行之前创建的吗?我还是不明白。
PositiveGuy 2010年

请参阅我对此的思考方式,即如果您的示例中没有GO,则首先创建Table,现在就在其中,因此插入应该起作用。如果我创建了表格,我将不知道GO的用途是什么...下一个插入内容可以使用它吗?!?!?!
PositiveGuy 2010年

2
@coffeeaddict:不。一口气就解析并编译了“批处理”。在编译时,dbo.TEST不存在。您没有实例化对象,并且SQL不是逐行的过程代码
gbn 2010年

3

众所周知,“ GO”不是T-SQL的一部分。“ GO”是SSMS中的批处理分隔符,SSMS是用于向数据库提交查询的客户端应用程序。这意味着声明的变量和表变量将不会从“ GO”之前的代码一直保留到其后的代码。

实际上,GO只是SSMS使用的默认单词。如果需要,可以在选项中进行更改。有点有趣,请更改其他人系统上的选项,以将“ SELECT”用作批处理分隔符而不是“ GO”。原谅我残酷的笑声。


1
这里实际上有一个很重要的观点:即使不是,您也应该将GO视为一个关键字。您也不应该更改它。重用特殊标识符引起的错误很难调试。
约根·福

@The Dixie Flatline:您确定声明的变量不持久吗?在MSSQL 2016中,运行时出现“已声明变量”错误:声明$ test int; 设置$ test = 5; 选择$ test go; 声明$ test int; -将$替换为<at>,不能在SE注释中使用多个<at>。
Wouter

0

它用于拆分逻辑块。您的代码被解释为sql命令行,这表明下一个代码块。

但是它可以用作具有特定编号的递归语句。

尝试:

exec sp_who2  
go 2

某些语句必须用GO分隔:

use DB
create view thisViewCreationWillFail
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.