我们都知道Sqlserver为了提高并发,允许乐观隔离级别(读提交快照,快照)以便读与写之间不阻塞.这里有一个在Sqlserver2008R2 SP2 的热补丁(CU11)下RCSI(读提交快照)隔离级别下的异常.希望大家注意.
这里我通过实例给大家呈现.
Code 测试数据 (Sql2008R2 sp2 cu11)
create database testbug
select @@VERSION --Microsoft SQL Server 2008 R2 (SP2) - 10.50.4302.0 (Intel X86)
use testbug
go
create table testbug
(
id int identity(1,1) primary key,
str1 char(10)
)
insert into testbug select 'aa'
go 10000
ALTER DATABASE testbug
SET READ_COMMITTED_SNAPSHOT ON
with rollback immediate-------------修改库隔离级别为RCSI
开启session 1,显式事务update
begin tran ttt
update testbug set str1='cc'
开启session 2,select 将被阻塞.
select * from testbug ---将被阻塞
出乎意料,不是说好的乐观隔离级别下读与写不阻塞吗??
原因分析
我们从DMV sys.dm_tran_locks中查看具体阻塞情况如图1-1
select * from sys.dm_tran_locks
图1-1
原来查询操作申请了IS锁,这里我可以通过trace flag 1200验证 如图1-2
DBCC TRACEON (3604,1200,-1)--------开启锁追踪输出
图1-2
在其他的数据库版本中(这里我测试了sql 2008R2 SP1,SP2,sql 2012 SP1)( 可以拿上面的测试脚本生成数据)
select 操作实际申请的锁sch-s架构共享锁,这个锁是和排他锁(X)兼容的如图1-3
图1-3
锁兼容实例如图1-4(锁兼容表)
图1-4
注意测试完成后我们关闭跟踪标记
DBCC TRACEOFF (3604,1200,-1)
可以看到在sql2008R2 CU11这个热补丁下读提交快照(RCSI)中同粒度下的读写会相互阻塞,这也违背了他提高并发的初衷,所以应该把它归结为异常.
影响版本:sql2008R2 SP2下 CU11,CU12,CU13热补丁
后记:原来已经有人提出了此BUG,微软将在接下来的版本(Sql2008R2SP3?)中解决此问题
https://connect.microsoft.com/SQLServer/feedback/details/914650/sql2008-r2-sp2-cu12-undermines-rcsi-by-making-select-statements-use-locks-instead-of-reading-row-versions
结语:在生产环境中我们可能会需要需要补丁来提高我们数据库的效率及健壮性等.但在打补丁前需要问下自己,为什么打补丁? Sqlserver补丁分为"SP","CU"两个粒度,CU属于及时调整修复,而SP是阶段性添补.我个人的经验是一般情况只打SP补丁(从这个实例可以看出,SP补丁一般很稳定:)),特殊需求下才打CU.