使用基于行版本控制的隔离级别
行版本控制框架在 SQL Server 中始终处于启用状态,并被多个功能使用。它除了提供基于行版本控制的隔离级别之外,还用于支持对触发器和多个活动结果集 (MARS) 会话的修改,以及 ONLINE 索引操作的数据读取。
基于行版本控制的隔离级别是在数据库级别上启用的。访问已启用数据库的对象的任何应用程序可以使用以下隔离级别运行查询:
已提交读隔离级别,通过将 READ_COMMITTED_SNAPSHOT 数据库选项设置为 ON 来使用行版本控制,如下面的代码示例所示:
ALTER DATABASE AdventureWorks2008R2 SET READ_COMMITTED_SNAPSHOT ON;
为 READ_COMMITTED_SNAPSHOT 启用数据库后,在已提交读隔离级别下运行的所有查询将使用行版本控制,这意味着读取操作不会阻止更新操作。
快照隔离,通过将 ALLOW_SNAPSHOT_ISOLATION 数据库选项设置为 ON 实现,如下面的代码示例所示:
ALTER DATABASE AdventureWorks2008R2 SET ALLOW_SNAPSHOT_ISOLATION ON;
在快照隔离下运行的事务可以访问数据库中为快照启用的表。若要访问没有为快照启用的表,则必须更改隔离级别。例如,下面的代码示例显示了在快照事务下运行时联接两个表的 SELECT 语句。一个表属于未启用快照隔离的数据库。当 SELECT 语句在快照隔离下运行时,该语句无法成功执行。
SET TRANSACTION ISOLATION LEVEL SNAPSHOT; BEGIN TRAN SELECT t1.col5, t2.col5 FROM Table1 as t1 INNER JOIN SecondDB.dbo.Table2 as t2 ON t1.col1 = t2.col2;
下面的代码示例显示了已修改为从事务隔离级别更改为已提交读隔离级别的相同 SELECT 语句。由于此更改,SELECT 语句将成功执行。
SET TRANSACTION ISOLATION LEVEL SNAPSHOT; BEGIN TRAN SELECT t1.col5, t2.col5 FROM Table1 as t1 WITH (READCOMMITTED) INNER JOIN SecondDB.dbo.Table2 as t2 ON t1.col1 = t2.col2;
有关在应用程序中如何设置隔离级别的详细信息,请参阅调整事务隔离级别。
使用基于行版本控制的隔离级别的事务的限制
使用基于行版本控制的隔离级别时,请考虑下列限制:
READ_COMMITTED_SNAPSHOT 无法在 tempdb、msdb 或 master 中启用。
全局临时表存储在 tempdb 中。访问快照事务中的全局临时表时,必须执行下列操作之一:
在 tempdb 中将 ALLOW_SNAPSHOT_ISOLATION 数据库选项设置为 ON。
使用隔离提示更改语句的隔离级别。
如果出现以下情况,快照事务将失败:
从快照事务启动之后到访问数据库前的期间内,数据库设置为只读。
如果访问多个数据库的对象,数据库状态以如下方式更改:从快照事务启动后到访问数据库前的期间内,发生数据库恢复。例如:将数据库设置为 OFFLINE,然后设置为 ONLINE,数据库将自动关闭和打开,或数据库将分离和附加。
快照隔离不支持分布式事务,包括分布式分区数据库中的查询。
SQL Server 不会保留多个版本的系统元数据。表中的数据定义语言 (DDL) 语句和其他数据库对象(索引、视图、数据类型、存储过程和公共语言运行时函数)会更改元数据。如果 DDL 语句修改一个对象,那么在快照隔离下对该对象的任何并发引用都将导致快照事务失败。READ_COMMITTED_SNAPSHOT 数据库选项为 ON 时,已提交读事务没有此限制。
例如,数据库管理员执行下面的 ALTER INDEX 语句。
USE AdventureWorks2008R2; GO ALTER INDEX AK_Employee_LoginID ON HumanResources.Employee REBUILD; GO
执行 ALTER INDEX 语句后,任何在执行 ALTER INDEX 语句时处于活动状态的快照事务,如果试图引用 HumanResources.Employee 表,都将收到错误。而使用行版本控制的已提交读事务不受影响。
注意 BULK INSERT 操作可能会导致对目标表元数据的更改(例如,禁用约束检查时)。如果出现这种情况,访问大容量插入表的并发快照隔离事务将失败。