你的位置:首页 > 数据库

[数据库]第18/24周 乐观并发控制(Optimistic Concurrency)


大家好,欢迎回到性能调优培训。上个星期我通过讨论悲观并发模式拉开了第5个月培训的序幕。今天我们继续,讨论下乐观并发模式(Optimistic Concurrency)

行版本(Row Versioning)

乐观并发模式自SQL Server 2005后引入,并基于行版本控制(Row Versioning)原则。行版本控制背后的想法是读操作(SELECT查询)不再需要获得共享锁(Shared Lock)。不去等待直到成功获得共享锁(Shared Lock),读操作是返回行前一个提交的版本。老的,前一个版本被存储在所谓的版本存储(Version Store)里,这个在TempDb里永驻。写操作(UPDATE,DELETE语句)明确复制老版本到版本存储,新版本在TempDb里指向老版本。下图诠释了这个概念。

 

增加这个指针的一个副作用是每个记录会增加额外的14 bytes。这会带来:

  • 堆表上的转发记录(Forwarding Records)
  • 聚集表上的页分裂(Page Splits)

另外,你也要按需计划和大小TempDb,因为你会引入额外的I/O,在默认配置下会带来竞争问题。现在让我们看看SQL Server提供给你的2个新的乐观隔离级别(optimistic isolation levels)。

乐观隔离级别(Optimistic Isolation Levels)

自SQL Server 2005起,关系引擎提供2个新的乐观隔离级别,它们是基于上一部分讨论过的行版本控制概念。

  • 读提交快照隔离(Read Committed Snapshot Isolation (RCSI))
  • 快照隔离(Snapshot Isolation (SI))

我们来详细看下这2个隔离级别。RCSI提供你基于快照语句级别的隔离。换句话说,SQL Server总会返回你在语句开始前有效的版本。它是提交读隔离级别(Read Committed Isolation Level)的乐观实现。因此使用这个隔离级别你会有不可重复读(Non-Repeatable Reads)。 

1 ALTER DATABASE AdventureWorks2012 SET READ_COMMITTED_SNAPSHOT ON2 GO3 4 -- Check if RCSI is now enabled5 SELECT name,is_read_committed_snapshot_on6 FROM sys.databases7 WHERE database_id = DB_ID('AdventureWorks2012')8 GO

RCSI的一个好处是对数据库/应用程序本身它是完全透明的:你重要在数据库上启用它,然后对于每个查询新的默认隔离级别是读提交快照隔离(Read Committed Snapshot Isolation)。因此通过对指定数据库启用RCSI,你可以克服锁和阻塞问题,即使死锁问题也很容易。下面代码显示了对于给出的数据库如何启用RCSI:

对于你SELECT查询,如果你想有重复读(Repeatable Reads)的乐观方式,你可以使用快照隔离(Snapshot Isolation (SI))隔离级别。快照隔离提供你开箱即用(out of box)的重复读,这就是说你总拿到在你事务开始前有效的行版本。遗憾的是快照隔离并不完全透明:

  • 快照隔离级别必须通过会话明确请求。因此在你的程序里你需要修改代码。
  • 你的查询会执行如所谓的更新冲突(Update Conflicts),SQL Server会回滚事务。因此在你的程序里你需要相应的进行处理这个情况。

下面代码向你展示了对于指定的数据库,如何启用快照隔离(Snapshot Isolation),如何请求这个新的隔离级别。

 1 -- Enable Snapshot Isolation (SI) 2 ALTER DATABASE AdventureWorks2012 SET ALLOW_SNAPSHOT_ISOLATION ON 3 GO 4  5 -- Check if SI is now enabled 6 SELECT name, snapshot_isolation_state, snapshot_isolation_state_desc 7 FROM sys.databases 8 WHERE database_id = DB_ID('AdventureWorks2012') 9 GO10 11 USE AdventureWorks201212 GO13 14 -- Setting the Isolation Level to Snapshot Isolation15 SET TRANSACTION ISOLATION LEVEL SNAPSHOT16 GO

小结

今天你学习了自SQL Server 2005起支持的2个乐观隔离级别。提交读快照隔离(Read Committed Snapshot Isolation (RCSI))提供你基于语句级别的隔离,快照隔离(Snapshot Isolation (SI))提供你基于事务级别的隔离,因为2个隔离级别使在永驻在TempDb里的版本存储,对于TempDb你需要仔细计划和指定标准。

下周我会谈下SQL Server 里锁和阻塞发生的问题:锁升级(Lock Escalations)。请继续关注!