SELECT
来创建事务是一种好的做法?这是什么代价
即使您使用的是
READ UNCOMMITTED
这样的隔离级别,这也是一个不好的做法吗?#1 楼
总是创建交易是不正确的做法吗?这取决于您在此讨论的上下文。如果是更新,则强烈建议显式使用TRANSACTIONS。如果是SELECT,则为NO(显式)。
但是首先要等待更多的了解:
sql server中的所有内容都包含在事务中。
当会话选项
IMPLICIT_TRANSACTIONS
为OFF
且您显式指定begin tran
和commit/rollback
时,这通常称为显式事务。否则,您将获得自动提交事务。当
IMPLICIT_TRANSACTIONS
为ON
时,执行联机丛书中记录的一种语句类型(例如SELECT
/ UPDATE
/ CREATE
)时,隐式事务会自动启动。明确提交或回滚。在这种模式下执行BEGIN TRAN
会增加@@TRANCOUNT
并启动另一个“嵌套”交易)要切换您所处的模式,请使用>
或
如果以上返回2,则您处于隐式事务处理模式。如果返回0,则表示您处于自动提交状态。
在不需要时创建事务的成本是多少?
需要进行事务处理才能从中获取数据库从一个一致状态变成另一个一致状态。事务是没有成本的,因为事务是不可替代的。
参考:使用基于行版本控制的隔离级别
,即使您使用的是隔离级别read_uncomitted。是不好的做法吗?
READ_UNCOMMITED隔离级别将允许按定义进行脏读,即一个事务将能够看到其他事务所做的未提交的更改。此隔离级别的作用是,它放松了锁定的开销-获取锁定以保护数据库并发的方法。
您可以在连接/查询级别使用它,这样它就不会影响其他查询。
SET IMPLICIT_TRANSACTIONS ON
发现了Jeff Atwood的一篇有趣的文章,描述了由于进餐哲学家而导致的死锁困惑并描述已提交的快照隔离级别。
编辑:
出于好奇,我进行了一些测试,以评估Perfmon计数器对T-log的影响,例如Log Bytes Flushed /秒,日志刷新等待数/秒(等待日志刷新发生的每秒提交数),如下图:
示例代码:
SET IMPLICIT_TRANSACTIONS OFF
select @@OPTIONS & 2
自动提交事务:(编辑为@TravisGan突出显示)
插入花费了19秒。
每次自动提交都会刷新由于自动完成(到@TravisGan突出显示之后,我错过了提及),将T-log缓冲区存入磁盘。
由于需要刷新的脏日志缓冲区数量较少,CHECKPOINT进程将很快完成。因为它经常安静地运行。
IMPLICIT和显式事务:
插入花费了2秒钟。
对于EXPLICIT事务,仅在日志缓冲区已满时才刷新它们。
与自动提交事务,在EXPLICIT事务中,CHECKPOINT进程将花费更长的时间,因为它将有更多的日志缓冲区要刷新(请记住,只有在缓冲区满时才刷新日志缓冲区)。
有一个DMV sys .dm_tran_database_transactions将返回有关数据库级别事务的信息。
显然,这是一种更为简单的测试,以显示影响。其他因素(如磁盘子系统,数据库自动增长设置,数据库的初始大小,在同一服务器\数据库上运行的其他进程等)也会产生影响。
从上述测试中,隐式和显式事务之间没有区别。
感谢@TravisGan帮助添加了更多答案。
评论
我已经看完了您的全部答案,但我不明白为什么您会说“如果是SELECT则否(明确)”。显式创建事务没有成本,那么仅针对单个SELECT创建事务有什么问题?即使没有必要,实际上也不应该是问题,对吗?
–杰兹
3月6日17:37
我很想知道您的用例,为什么要使用事务进行选择级别与隔离级别,例如读取脏数据?
–金沙(Kin Shah)
3月6日18:45
#2 楼
SQL语句始终在事务中运行。如果不显式启动一个语句,则每个SQL语句都将在其自身的一个事务中运行。唯一的选择是是否在一个事务中捆绑多个语句。跨多个语句的事务会留下损害并发性的锁。因此,“总是”创建交易不是一个好主意。您应该在成本与收益之间取得平衡。
评论
“ SQL语句始终在事务中运行”。有文件确认吗?
– liang
7月21日,3:12
#3 楼
问题在于,是否必须将一组操作视为单个操作。换句话说,所有操作都必须成功完成并提交,否则任何操作都不能提交。如果您的情况要求您读取初步数据,然后根据该数据执行更新,则首先读取
注意:我避免故意选择/插入/更新。交易范围实际上可能是在应用程序级别,并且涉及多个数据库操作。
考虑经典模式,例如飞机座位预订或银行余额查询/取款。确保整个应用程序产生可靠,一致的数据的问题。
评论
看看BEGIN TRAN SELECT ... COMMIT与SELECT的影响,似乎存在很小的性能差异。