编写有效的事务
尽可能使事务保持简短很重要。当事务启动后,数据库管理系统 (DBMS) 必须在事务结束之前保留很多资源,以保护事务的原子性、一致性、隔离性和持久性 (ACID) 属性。如果修改数据,则必须用排他锁保护修改过的行,以防止任何其他事务读取这些行,并且必须将排他锁控制到提交或回滚事务时为止。根据事务隔离级别设置,SELECT 语句可以获取必须控制到提交或回滚事务时为止的锁。特别是在有很多用户的系统中,必须尽可能使事务保持简短以减少并发连接间的资源锁定争夺。在有少量用户的系统中,运行时间长、效率低的事务可能不会成为问题,但是在有上千个用户的系统中,将不能忍受这样的事务。
编码指导原则
以下是编写有效事务的指导原则:
不要在事务处理期间要求用户输入。
在事务启动之前,获得所有需要的用户输入。如果在事务处理期间还需要其他用户输入,则回滚当前事务,并在提供了用户输入之后重新启动该事务。即使用户立即响应,作为人,其反应时间也要比计算机慢得多。事务占用的所有资源都要保留相当长的时间,这有可能会造成阻塞问题。如果用户没有响应,事务仍然会保持活动状态,从而锁定关键资源直到用户响应为止,但是用户可能会几分钟甚至几个小时都不响应。
在浏览数据时,尽量不要打开事务。
在所有预备的数据分析完成之前,不应启动事务。
尽可能使事务保持简短。
在知道要进行的修改之后,启动事务,执行修改语句,然后立即提交或回滚。只有在需要时才打开事务。
若要减少阻塞,请考虑针对只读查询使用基于行版本控制的隔离级别。有关详细信息,请参阅使用基于行版本控制的隔离级别。
灵活地使用更低的事务隔离级别。
可以很容易地编写出许多使用只读事务隔离级别的应用程序。并不是所有事务都要求可序列化的事务隔离级别。
灵活地使用更低的游标并发选项,例如开放式并发选项。
在并发更新的可能性很小的系统中,处理“别人在您读取数据后更改了数据”的偶然错误的开销要比在读取数据时始终锁定行的开销小得多。
在事务中尽量使访问的数据量最小。
这样可以减少锁定的行数,从而减少事务之间的争夺。
避免并发问题和资源问题
为了防止并发问题和资源问题,应小心管理隐式事务。使用隐式事务时,COMMIT 或 ROLLBACK 后的下一个 Transact-SQL 语句会自动启动一个新事务。这可能会在应用程序浏览数据时(甚至在需要用户输入时)打开一个新事务。在完成保护数据修改所需的最后一个事务之后,应关闭隐性事务,直到再次需要使用事务来保护数据修改。此过程使 SQL Server 数据库引擎 能够在应用程序浏览数据以及获取用户输入时使用自动提交模式。
另外,启用快照隔离级别后,尽管新事务不会控制锁,但是长时间运行的事务将阻止从 tempdb 中删除旧版本。