在仅有SELECT操作的事务中,提交(commit)和回滚(rollback)之间有区别吗?

21

在我们公司使用的自有应用程序框架中,即使我知道没有任何命令会改变数据库,也必须将每个SQL查询放入事务中。在会话结束之前,在关闭连接之前,我提交事务以正确关闭它。我想知道如果我回滚事务是否会有特别的差异,尤其是在速度方面。

请注意,我正在使用Oracle,但我猜其他数据库具有类似的行为。此外,我无法对需要开始事务的要求做任何事情,这部分代码库不在我的控制范围内。

7个回答

14

数据库通常保存一个前像日志(事务之前的状态)或后像日志(事务完成后的状态)。如果它保存了前像,那么在回滚时必须还原该值。如果它保存了后像,则在提交事件发生时必须替换数据。

Oracle拥有日志和回滚空间。事务日志累积块,稍后由DB编写器编写。由于这些是异步的,几乎没有任何与DB编写器相关的事情会影响您的事务(如果队列填满,则您可能需要等待)。

即使对于仅查询的事务,我也愿意打赌Oracle的回滚区域中也有一些小的事务记录跟踪。我怀疑回滚需要Oracle在确定实际上没有要回滚的内容之前进行一些工作。而我认为这与您的事务同步。在回滚完成之前,您无法释放任何锁定。[是的,我知道您在事务中没有使用任何锁定,但这个锁定问题就是我认为必须完全释放回滚,然后才能释放所有锁定,然后您的回滚才完成的原因。]

另一方面,提交是预期的结果,我认为放弃回滚区域可能会稍微快一些。由于您没有创建任何事务记录,因此DB编写器甚至不会醒来检查并发现没有要完成的任务。

我还预计,虽然提交可能更快,但差异将是微小的。如此微小,以至于您可能无法在并排比较中测量它们。


5
我不认为这是 Oracle 工作方式的描述。它听起来像是一个泛泛而谈的描述被套用到了 Oracle 上。对 Oracle 工作方式的猜测并不太有帮助。 - David Aldridge
Oracle将日志称为“重做日志文件”,将回滚段称为“撤消表空间”。你知道哪个更快吗?提交还是回滚? - S.Lott
如果没有工作要做,那么几乎没有什么区别。Oracle被优化为快速提交——它只需要将提交记录写入重做日志缓冲区并刷新缓冲区(除了10g+中的异步提交)。回滚是更多的工作。 - David Aldridge
1
在http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1519405621318#tom64214016687322上,Tom Kyte指出如果没有事务,数据库实际上不会执行任何提交工作。您可以通过快速执行几百个提交并检查日志文件同步事件的计数来验证这一点。 - Gary Myers

8
我同意之前的答案,对于这种情况COMMIT和ROLLBACK没有区别。在确定没有需要提交或回滚的内容时,所需的CPU时间可能略有不同,但如果这只是微不足道的差异,我们可以安全地忘记它。
然而,值得指出的是,在单个事务的上下文中执行一堆查询和在一系列事务的上下文中执行相同查询的会话之间存在差异。
如果客户端启动一个事务,执行一个查询,执行COMMIT或ROLLBACK,然后启动第二个事务并执行第二个查询,则无法保证第二个查询将观察到与第一个查询相同的数据库状态。有时,维护单个一致的数据视图至关重要。有时,获取更实时的数据视图至关重要。这取决于你正在做什么。
我知道,我知道,OP没有问这个问题。但是一些读者可能会在心里问它。

3

通常情况下,提交(COMMIT)比回滚(ROLLBACK)快得多,但在您什么也没做的情况下,它们实际上是相同的。


3
文档说明:
Oracle建议您在应用程序中显式地使用COMMIT或ROLLBACK语句结束每个事务,包括最后一个事务,然后再断开与Oracle数据库的连接。如果您没有显式提交事务并且程序异常终止,则最后一个未提交的事务将自动回滚。从大多数Oracle实用程序和工具正常退出会导致当前事务被提交。从Oracle预编译程序正常退出不会提交事务,并依赖于Oracle数据库来回滚当前事务。 http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/statements_4010.htm#SQLRF01110 如果您想选择其中之一,那么您可能就像什么都没做一样,只需提交即可。

实际上这取决于客户端。对于sqlplus,它是一个隐式提交。而对于其他情况可能不是这样。如果网络连接中断(例如,客户端突然“消失”),那么就会回滚。 - Matthew Watson
我不确定它是否取决于应用程序,我可能应该说“优雅断开连接”,但文档中说:“在应用程序正常终止后会发生隐式请求或...”http://download.oracle.com/docs/cd/B28359_01/server.111/b28318/transact.htm#CNCPT1119 - David Aldridge
实际上,我找到了一个更好的参考资料,并编辑了我的帖子。谢谢。 - David Aldridge

1

嗯,我们必须考虑Oracle中SELECT返回的内容。有两种模式。默认情况下,SELECT将数据作为在执行SELECT语句开始时该数据所呈现的样子返回(这是READ COMMITTED隔离模式(默认事务模式)的默认行为)。因此,如果在发出SELECT之后执行了UPDATE / INSERT,则不会在结果集中显示。

如果您需要比较两个结果集(例如总分类账应用程序的借方和贷方),则可能会遇到问题。对于这种情况,我们有第二种模式。在该模式下,SELECT将返回数据,就像当前事务开始时看起来一样(READ ONLY和SERIALIZABLE隔离级别的默认行为)。

因此,至少有时候需要在事务中执行SELECT。


0
我认为提交操作会更有效率,因为通常你会期望大多数数据库事务都被提交,所以你会认为数据库会针对这种情况进行优化(而不是试图在回滚时更加高效)。

0

由于您尚未执行任何DML操作,我怀疑在Oracle中提交(COMMIT)和回滚(ROLLBACK)之间没有区别。无论哪种方式,都不需要进行任何操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接