内存优化表(Memory-Optimized Table,简称MOT)使用乐观策略(optimistic approach)实现事务的并发控制,在读取MOT时,使用多行版本化(Multi-Row versioning)创建数据快照,读操作不会对数据加锁,因此,读写操作不会相互阻塞。写操作会申请行级锁,如果两个事务尝试更新同一数据行,SQL Server检测到写-写冲突,产生错误(Error 41302),将后后创建的事务作为失败者,回滚事务的操作。虽然MOT事务使用无锁结构(Lock-Free),不会产生阻塞,但是,访问MOT仍然会产生Wait,通常情况下,等待时间是非常短暂的。

一,MOT使用乐观并发事务控制

1,并发控制策略

事务的并发控制策略分为乐观策略和悲观策略,SQL Server支持两种并发策略。

1.1,悲观策略(Pessimistic Approach)

悲观策略认为每一个数据更新都潜在地存在冲突,为了避免数据争用,事务在读取数据时申请共享锁,在更新数据时对数据加互斥锁(Locking)。在冲突发生时,通过加锁阻塞其他事务;其他事务检测到冲突后,等待拥有资源的事务释放互斥锁,其他事务只有获取到资源上的加锁,才能执行读写操作。

悲观策略主要用于数据争用激烈,并且发生发冲突时用锁保护数据的成本低于回滚事务的成本的环境中。

1.2,乐观策略(Optimistic Approach)

乐观策略认为执行的数据更新操作很少存在冲突,事务在读取数据时,不锁定数据;在更新数据时,事务只在提交时检查更新的有效性,如果有其他事务更新该数据,将产生更新冲突的错误,那么事务不等待,SQL Server选择一个事务作为失败者,并回滚事务执行的操作。乐观策略效率更高,部分原因是在大多数情况下,更新冲突不经常发生。当冲突发生时,使用悲观策略,事务需要等待;使用乐观策略,SQL Server使事务失败,回滚事务操作。

乐观策略主要用于数据争用不大,并且偶尔回滚事务的成本低于读取数据时锁定数据的成本的环境中。

乐观估计效率更高,部分原因是在大多数情况下,事务冲突不经常发生。当冲突发生时,使用悲观估计法,事务需要等待;使用乐观估计法,SQL Server使事务失败,并回滚事务操作,因此,在发生更新冲突时,需要在客户端进行异常检测,重新执行事务。

2,MOT使用乐观并发控制(Optimistic Concurrency Control,简称OCC)

乐观策略使用行版本化(row versioning)实现并发控制,对于disk-based table,使用tempdb存储行版本数据;对于MOT,在内存中存储行版本数据。

乐观策略认为冲突和失败是不常见的,OCC认为访问MOT的事务不会和其他并发执行的事务产生冲突,任何操作都会执行成功。在访问MOT时,事务不会加锁(Lock或Latch)以保证读操作的隔离性,因此,读写操作互不阻塞,也不会产生等待。一旦产生写-写冲突,SQL Server将选择创建时间晚的事务作为失败者,并回滚该事务操作。

二,MOT支持的事务隔离级别(Transaction Isolation Level)

在In-Memory OLTP系统中,存在两种事务隔离级别,访问硬盘表(Disk-Based Table,简称DBT)的事务,和访问MOT的事务;和传统的事务隔离级别不同,在一个事务中,存在两个隔离级别。

1,MOT的SNAPSHOT隔离级别

实际上,访问MOT,事务必须处在SNAPSHOT隔离级别下,SNAPSHOT隔离级别指定在读操作执行时,数据在事务级别保持一致性,这意味着,在一个事务中的任何读操作,读取的数据是事务一致性的数据版本。事务一致性是指在事务开始时,创建数据快照:在事务开始时,已经提交的事务更新,能够被该事务识别;在事务开始之后,被其他事务提交的数据更新操作,不会被当前事务识别。

This isolation level specifies that data read by any statement in a transaction will be the transactionally consistent version of the data that existed at the start of the transaction. The transaction can only recognize data modifications that were committed before the start of the transaction. Data modifications made by other transactions after the start of the current transaction are not visible to statements executing in the current transaction. The statements in a transaction get a snapshot of the committed data as it existed at the start of the transaction.

在SQL Server 2016中,有两种方式指定隔离级别:当在解释性TSQL中访问MOT时,使用Table Hint指定SNAPSHOT隔离级别;当在Natively Compiled 存储过程中访问MOT时,必须在Atomic Block中指定隔离级别为SNAPSHOT。

SNAPSHOT隔离级别只会影响读操作,而写操作不受隔离级别的影响,和其他事务完全隔离,因此,在Snapshot隔离级别下,当并发事务尝试去更新同一行数据时,并发事务产生更新冲突,抛出错误 41302,41325,或41305,SQL Server选择一个开始时间晚的事务作为失败者,并回滚其操作,产生的Error是:

  • Error 41302. The current transaction attempted to update a record in table X that has been updated since this transaction started. The transaction was aborted. When the current transaction attempts to insert a row with the same primary key value as a row that was inserted by another transaction that committed before the current transaction, there will be a failure to commit with the following error message.
  • Error 41325. The current transaction failed to commit due to a serializable validation failure. If a transaction writes to a table that is dropped before the transaction commits, the transaction terminates with the following error message:
  • Error 41305. The current transaction failed to commit due to a repeatable read validation failure.

2,提升事务的隔离级别

在显式事务(Explicit)模式中,如果默认的事务隔离级别低于SNAPSHOT,那么必须提升事务隔离级别,才能访问MOT,有两种实现方式: 

  • 设置数据库选项 MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT 为ON,该选项的作用是:当事务隔离级别比SNAPSHOT低时(比如,READ COMMITTED or READ UNCOMMITTED),访问MOT的事务都会自动升级到SNAPSHOT隔离级别:
  • ALTER DATABASE CURRENT SET MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT=ON 
  • 为MOT使用Table Hint:with(snapshot)

因此,在显式事务中,通过解释性(Interpreted)TSQL访问MOT时,必须:

  • 使用Table Hint指定隔离级别:WITH(SNAPSHOT),WITH(REPEATABLEREAD) 和 WITH(SERIALIZABLE) 
  • 设置数据库选项:MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT 为ON

如果发生MSSQLSERVER_41333 错误,说明产生交叉事务隔离错误(CROSS_CONTAINER_ISOLATION_FAILURE),原因是当前事务的隔离级别太高,解决方法是:将Session-Level的事务隔离级别降低到Read Committed。

3,事务初始化模式(Transaction Initiation Modes)

SQL Server 支持四种事务初始化模式:
  • Autocommit:自动提交模式(默认模式),将单个语句作为一个事务,在语句开始时,隐式开始一个事务;在语句结束时,隐式提交该事务;
    • 在autocommit模式下,访问MOT不需要使用Table Hint指定事务隔离级别;SQL Server自动为MOT应用SNAPSHOT隔离。
  • Explicit:显式模式,使用begin tran 显式开始一个事务,使用commit tran 提交事务,或使用rollback tran 回滚事务。在显式事务中,将事务中的一个,或多个查询语句作为单个事务进行处理;
    • 在显式模式下,访问MOT必须使用SNAPSHOT隔离级别,通过使用Table Hint 指定SNAPSHOT 隔离级别,
    • 或设置数据库选项 MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT 为ON来实现;
  • Implicit:隐式模式,查询语句隐式开始一个事务,必须显式使用commit tran 提交事务,或使用rollback tran回滚事务。使用该模式,必须设置选项:
    SET IMPLICIT_TRANSACTION ON
  • Atomic block:原子块模式,只能用于Natively Compiled SP中。在Atomic block中的所有查询语句都作为单个事务提交或回滚。
    • 在Atomic block中,支持的事务隔离级别是:TRANSACTION ISOLATION LEVEL = { SNAPSHOT | REPEATABLE READ | SERIALIZABLE }  
    • 在Natively Compiled SP中,使用BEGIN ATOMIC WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, ...) 定义Atomic block事务:
      create procedure schema_name.sp_name
      with native_compilation, schemabinding, execute as owner  
      as
      begin atomic with (transaction isolation level=snapshot, language=N'us_english') 
          statement1;
          statement2;
          ....
      end 
      View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-06-28
  • 2021-07-14
  • 2021-04-22
猜你喜欢
  • 2022-01-21
  • 2021-06-09
  • 2021-06-04
  • 2021-06-09
  • 2022-02-22
  • 2021-11-23
  • 2021-11-14
相关资源
相似解决方案