所以我运行了带有一堆UPDATE语句的SQL批处理:
UPDATE...;
UPDATE...;
UPDATE...;
结果表明批处理是作为单个事务运行的,因此创建了许多锁(我们的数据库监视软件清楚地表明这是一个大事务),因此,显然类似于我围绕该批处理写BEGIN ... COMMIT:
BEGIN TRANS;
UPDATE...;
UPDATE...;
UPDATE...;
COMMIT;
真的是这样吗?批次是否总是作为一个事务执行? (我不是处于“显式事务”模式),为什么要这样做,可以对其进行配置,还是仅仅是SQL Server的行为?
如果我将每条语句都包装在BEGIN..COMMIT中,它将发生什么变化?
BEGIN TRANS;
UPDATE...;
COMMIT;
BEGIN TRANS;
UPDATE...;
COMMIT;
BEGIN TRANS;
UPDATE...;
COMMIT;
谢谢!
答案 0 :(得分:0)
假设您正在从SSMS查询窗口执行更新,则可以将代码重构为
BEGIN TRANS;
UPDATE...;
GO
UPDATE...;
GO
UPDATE...;
GO
COMMIT;
GO将使每个UPDATE按调用的顺序在其自己的批处理中优先执行,但是直到最后一次COMMIT调用时才会提交。
我已经通过以下示例对此进行了测试,您可以在SSMS中自行运行。
SET NOCOUNT ON
GO
IF EXISTS ( SELECT * FROM sys.tables WHERE name = 'BatchTest' )
DROP TABLE dbo.BatchTest;
GO
CREATE TABLE dbo.BatchTest (
id INT IDENTITY (1,1) PRIMARY KEY NOT NULL
, col1 VARCHAR(50)
, col2 VARCHAR(50)
, col3 VARCHAR(50)
, col4 VARCHAR(50)
)
GO
DECLARE @i INT = 1;
WHILE ( @i <= 100 ) BEGIN
INSERT INTO dbo.BatchTest ( col1 ) VALUES ( 'col1_' + CAST ( @i AS VARCHAR(10) ) );
SET @i += 1;
END
GO
SELECT * FROM dbo.BatchTest ORDER BY id;
/*
-- test tran/commit --
-- manually select and execute the code below after the BatchTest has been created and populated with data --
SET NOCOUNT ON
GO
BEGIN TRAN;
UPDATE dbo.BatchTest SET col2 = 'col2_' + CAST ( id AS VARCHAR(10) );
GO
UPDATE dbo.BatchTest SET col3 = 'col3_' + CAST ( id AS VARCHAR(10) );
GO
UPDATE dbo.BatchTest SET col4 = 'col4_' + CAST ( id AS VARCHAR(10) );
GO
--COMMIT;
ROLLBACK;
SELECT * FROM dbo.BatchTest ORDER BY id;
*/
请注意代码中有关选择和执行tran / commit测试的注释。
单个ROLLBACK撤消当前事务中的所有UPDATE,而与使用GO无关,而COMMIT将全部提交它们。显然,您应该多加努力,对数据进行测试,但这可能会有助于解决锁定问题。
有关SQL Server使用GO及其意图的一些后续阅读: https://docs.microsoft.com/en-us/sql/t-sql/language-elements/sql-server-utilities-statements-go?view=sql-server-2017