大家好,欢迎回到性能调优培训。上个星期我通过讨论悲观并发模式拉开了第5个月培训的序幕。今天我们继续,讨论下乐观并发模式(Optimistic Concurrency)。
行版本(Row Versioning)
乐观并发模式自SQL Server 2005后引入,并基于行版本控制(Row Versioning)原则。行版本控制背后的想法是读操作(SELECT查询)不再需要获得共享锁(Shared Lock)。不去等待直到成功获得共享锁(Shared Lock),读操作是返回行前一个提交的版本。老的,前一个版本被存储在所谓的版本存储(Version Store)里,这个在TempDb里永驻。写操作(UPDATE,DELETE语句)明确复制老版本到版本存储,新版本中含一个指针指向versionstore里面旧行。下图诠释了这个概念。
增加这个指针的一个副作用是每个记录会增加额外的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 ON 2 GO 3 4 -- Check if RCSI is now enabled 5 SELECT name,is_read_committed_snapshot_on 6 FROM sys.databases 7 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 GO 10 11 USE AdventureWorks2012 12 GO 13 14 -- Setting the Isolation Level to Snapshot Isolation 15 SET TRANSACTION ISOLATION LEVEL SNAPSHOT 16 GO
小结
今天你学习了自SQL Server 2005起支持的2个乐观隔离级别。提交读快照隔离(Read Committed Snapshot Isolation (RCSI))提供你基于语句级别的隔离,快照隔离(Snapshot Isolation (SI))提供你基于事务级别的隔离,因为2个隔离级别使在永驻在TempDb里的版本存储,对于TempDb你需要仔细计划和指定标准。
下周我会谈下SQL Server 里锁和阻塞发生的问题:锁升级(Lock Escalations)。请继续关注!