Answers:
本身进行公开交易几乎不会有任何后果。一个简单的
BEGIN TRANSACTION
-- wait for a while, doing nothing
-- wait a bit longer
COMMIT
在最坏的情况下,将保留几个字节的状态值。没什么大不了的。
大多数程序将在事务内完成实际工作,这是另一回事。事务的重点是,即使有其他用户同时写入同一数据库,您也可以确保数据库中的多个事实同时成立。
以在银行帐户之间转移资金的典型例子为例。系统必须确保源帐户存在,有足够的资金,目标帐户存在,并且借方和贷方都发生或不发生。它必须在其他交易发生时甚至在这两个帐户之间进行交易时保证这一点。系统通过在相关表上锁定来确保这一点。采取什么锁以及您看到多少其他人的工作由事务隔离级别控制。
因此,如果您做了很多工作,很有可能其他事务将排队等待您持有锁的对象。这将降低系统的整体吞吐量。最终,它们将达到超时限制并失败,这是整个系统行为的问题。如果使用乐观隔离级别,则由于其他人的工作,当您尝试提交时,事务可能会失败。
持有锁会占用系统资源。这是系统无法用于处理其他请求的内存,从而降低了吞吐量。
如果执行了大量工作,则系统可以选择执行锁定升级。而不是锁定单个行,整个表将被锁定。然后,更多的并发用户将受到影响,系统吞吐量将进一步下降,并且对应用程序的影响将更大。
数据更改以及保护它们的锁都会写入日志文件。在事务提交之前,无法从日志中清除这些内容。因此,很长的事务可能会导致日志文件膨胀以及相关的问题。
如果当前工作使用的是tempdb(可能适用于大型工作负载),则那里的资源可能会被占用,直到事务结束。在极端情况下,这可能会导致其他任务失败,因为不再有足够的空间容纳它们。我曾经遇到过这样的情况,即编码不足的UPDATE填充了tempdb,因此没有足够的磁盘用于报告的SORT,并且报告失败。
如果选择回滚事务,或者系统发生故障并恢复,则系统再次可用所需的时间将取决于执行了多少工作。简单地打开一个事务不会影响恢复时间,这是执行了多少工作。如果事务已打开但闲置了一个小时,则恢复几乎是瞬时的。如果在该小时内不断写作,则经验法则是恢复时间也将是一个小时左右。
如您所见,长时间的交易可能会出现问题。对于OLTP系统,最佳实践是每个业务事务只有一个数据库事务。对于批处理工作,以频繁提交的块形式输入过程,并重新编码逻辑。通常,在一个数据库事务中可以处理几千条记录,但是应该测试并发性并减少消耗。
不要试图走到另一个极端,避免交易和完全锁定。如果您需要保持数据内的一致性(以及为什么还要使用数据库?),隔离级别和事务将起到非常重要的作用。了解有关您的选项的信息,并确定在应用程序的每个部分中准备使用的并发性和正确性之间的平衡。
您最大的后果将是阻塞事务中使用的对象。特别是如果您假设用户正在插入数据,则该长时间运行的事务可能会在常用表上包含SELECT语句。用户的更新语句可能无法获得完成其更新或插入所需的必要锁定。
可能发生的第二件事是日志文件活动,例如,如果您要更新大型数据集,则在该事务期间,事务正在使用的日志部分将保持活动状态。在事务被提交或回滚之前,您将无法重用该部分日志。在您可能处于活动频繁的OLTP系统中的情况下,这可能会导致日志文件快速增长,从而填满存储设备。
不完整的事务可能持有大量锁并导致阻塞
如果由于查询超时或由于在事务中间取消了批处理而未发出COMMIT或ROLLBACK语句来完成事务而未完成事务,则该事务将保持打开状态,并且在该事务期间获取的所有锁将继续将要举行。在同一连接下执行的后续事务将被视为嵌套事务,因此不会释放在这些完成的事务中获取的所有锁。从同一连接执行的所有事务都会重复出现此问题,直到执行ROLLBACK。结果,持有大量锁,用户被阻止,交易丢失,从而导致数据与您期望的数据不同。