总是创建交易是不好的做法吗?


88

总是创建交易是不好的做法吗?

例如,优良作法是只创建一个简单的交易SELECT

在没有必要的情况下创建交易的成本是多少?

即使您使用隔离级别,例如READ UNCOMMITTED,这也是一个不好的做法吗?


1
BEGIN TRAN SELECT ... COMMIT对比vs的影响SELECT看来,性能差异很小
马丁·史密斯

Answers:


100

创建交易总是一个坏习惯吗?

这取决于您在这里所说的上下文。如果是更新,则强烈建议显式使用TRANSACTIONS。如果是SELECT,则为NO(显式)。

但是,首先要了解的还有更多:sql server中的所有内容都包含在一个事务中。

当session选项IMPLICIT_TRANSACTIONSOFF且您显式指定时begin trancommit/rollback通常称为“ 显式事务”。否则,您将获得自动提交事务。

IMPLICIT_TRANSACTIONSON一个隐性事务执行的书网上的文章(如记录的类型的语句时,会自动启动SELECT/ UPDATE/ CREATE),它必须被提交或回滚明确。BEGIN TRAN以这种模式执行会增加@@TRANCOUNT并启动另一个“嵌套”交易)

要切换您所处的模式,请使用

SET IMPLICIT_TRANSACTIONS ON

要么

SET IMPLICIT_TRANSACTIONS OFF

select @@OPTIONS & 2

如果以上返回2,则您处于隐式事务模式。如果返回0,则表示您处于自动提交状态。

在没有必要时创建交易的成本是多少?

需要进行事务处理才能使数据库从一个一致状态进入另一个一致状态。交易没有成本,因为没有其他选择可以交易。参考:使用基于行版本控制的隔离级别

即使您使用的是隔离级别read_uncomitted。是不好的做法吗?因为它应该不会出现锁定问题。

READ_UNCOMMITED隔离级别将允许按定义进行脏读,即,一个事务将能够看到其他事务所做的未提交的更改。此隔离级别的作用是,它放宽了锁定的开销-获取锁定以保护数据库并发的方法。

您可以在连接/查询级别使用它,这样它就不会影响其他查询。

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

发现了Jeff Atwood的一篇有趣的文章,它描述了由于Dining Philosophers Puzzle造成的死锁,并描述了已 提交的快照隔离级别。

编辑:

出于好奇,我进行了一些测试,使用Perfmon计数器测量对T-log的影响,例如Log Bytes Flushed / Sec,Log Flush Waits / Sec(等待LOG刷新发生的每秒提交数),如下图所示:

在此处输入图片说明

样例代码:

create table testTran (id int, Name varchar(8))
go

-- 19 sec
-- Autocommit transaction
declare @i int
set @i = 0
while @i < 100000
begin 
insert into testTran values (1,'Kin Shah')
set @i = @i+1
end
---------------------------------------------------
-- 2 sec
-- Implicit transaction
SET IMPLICIT_TRANSACTIONS ON
declare @i int
set @i = 0
while @i < 100000
begin 
insert into testTran values (1,'Kin Shah')
set @i = @i+1
end
COMMIT;
SET IMPLICIT_TRANSACTIONS OFF


----------------------------------------------------
-- 2 sec
-- Explicit transaction
declare @i int
set @i = 0
BEGIN TRAN
WHILE @i < 100000
Begin
INSERT INTO testTran values (1,'Kin Shah')
set @i = @i+1
End
COMMIT TRAN

自动提交事务:(由@TravisGan突出显示)

  • 插入耗时19秒。
  • 每次自动提交都会由于自动提交而将T-log缓冲区刷新到磁盘(在@TravisGan突出显示之后,我错过了提及)。
  • CHECKPOINT进程将很快完成,因为需要刷新的脏日志缓冲区的数量会减少,因为它经常安静地运行。

隐式和显式交易:

  • 插入耗时2秒。
  • 对于EXPLICIT事务,仅在日志缓冲区已满时才刷新它们。
  • 与自动提交事务相反,在EXPLICIT事务中,CHECKPOINT进程将花费更长的时间,因为它将有更多的日志缓冲区要刷新(请记住,只有在缓冲区已满时才刷新日志缓冲区)。

有一个DMV sys.dm_tran_database_transactions将返回有关数据库级别事务的信息。

显然,这是一种更简单的测试来显示影响。其他因素(如磁盘子系统,数据库自动增长设置,数据库的初始大小,在同一服务器\数据库上运行的其他进程等)也会产生影响。

通过以上测试,隐式和显式事务之间几乎没有差异。

感谢@TravisGan为帮助添加更多答案。


35

SQL语句始终在事务中运行。如果不显式启动一个语句,则每个SQL语句都会在自身的事务中运行。

唯一的选择是是否在一个事务中捆绑多个语句。跨多个语句的事务会留下损害并发性的锁。因此,“总是”创建交易不是一个好主意。您应该权衡成本与收益。


1

问题在于,是否必须将一组操作视为单个操作。换句话说,所有操作都必须成功完成并提交,否则任何操作都不能提交。如果您有需要先读取初步数据然后根据该数据执行更新的情况,则初始读取可能应该是事务的一部分。注意:我避免故意选择/插入/更新。事务范围实际上可能在应用程序级别,并且涉及多个数据库操作。考虑一下经典模式,例如飞机座位预订或银行余额查询/提款。必须对问题进行更广泛的了解,以确保整个应用程序产生可靠,一致的数据。

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.