聚集索引可提高并发性--
地宝原创,转贴请注明出自微软BI开拓者www.windbi.com一个网友的问题:
在如下的表中
create table t (f int)
insert into t values (1)
insert into t values(2)
insert into t values(3)
insert into t values(4)
当在默认的事务隔离级别下(READ COMMITTED):
事务A:
begin tran
update t set f=0 where f=1
waitfor delay '00:00:10'
rollback tran
事务B:
begin tran
update t set f=9 where f=4
rollback tran
为什么事务B会被事务A所阻挡直至事务A运行结束?
事务A与事务B加的锁不是在同一条数据上呀?
我回答说这是因为没有建立聚集索引的原因。
他大不解,我为他做了详细的介绍。
首先我们看看当事务运行是会加什么锁,当事务A运行后,我们再开一进程,输入sp_lock:
58 1 257435991 0 TAB IX GRANT
58 1 257435991 0 PAG 1:343 IX GRANT
58 1 257435991 0 RID 1:343:0 X GRANT
我们会发现事务A运行后,对where f=1行中加行锁,在页与表上加IX意向锁(若不清楚这些锁类型,就到联机帮助中找,很详细的)。
然后我们在A事务运行后,运行B事务,再用sp_lock看一下:
58 1 273436048 0 PAG 1:343 IX GRANT
58 1 273436048 0 RID 1:343:0 X GRANT
58 1 273436048 0 TAB IX GRANT
59 1 273436048 0 TAB IX GRANT
59 1 273436048 0 RID 1:343:0 U WAIT
59 1 273436048 0 PAG 1:343 IU GRANT
大家注意一下那个 WAIT 对应的锁的项目是U(更新锁)
什么是更新锁大家可参考联机帮助,我简单的讲,U锁就是用在那些先进行搜索后更新数据的语句上
如:update t set f=9 where f=4 中,在搜索时,会使用更新锁先加在那些扫描的数据上,当找到目标
数据后,再转换为X锁。但U锁与X锁是不相容的,也就是说只有一方释放后另一方才会获得。
这是我们就进入到真正的主题了,为什么是没有建立索引而产生的问题。
当表中没有索引时,在运行
update t set f=9 where f=4
时,会对表进行表扫描,当扫描到 RID 1:343:0 时(也就是f=1)时,要对 RID 1:343:0 加U锁,可
RID 1:343:0上的X锁尚未释放,因此U锁只有等待,因此B事务只有等待A事务的结束而执行。
那对f使用了聚集索引会产生什么效果呢?
加上索引:
create clustered index IX_f on t(f)
再次运行,B事务没有被阻挡,那究竟是为什么呢,我们在改变一下B事务的运行方式:
begin tran
update t set f=9 where f=4
waitfor delay '00:00:10'
rollback tran
在依次执行A、B事务后,运行sp_lock:
58 1 273436048 1 KEY (0000e208dd39) X GRANT
58 1 273436048 1 PAG 1:353 IX GRANT
58 1 273436048 1 KEY (01005221bd04) X GRANT
58 1 273436048 0 TAB IX GRANT
59 1 273436048 1 KEY (0900936acd34) X GRANT
59 1 273436048 0 TAB IX GRANT
59 1 273436048 1 KEY (040022ae5dcc) X GRANT
59 1 273436048 1 PAG 1:353 IX GRANT
大家会发现
RID 1:343:0 消失了,代替的是KEY,这就是索引了,由于聚集索引的出现因此在使用
update t set f=9 where f=4是不需要表扫描,会直接定位到一个KEY上,而f=4上没有X锁,
因此,B事务不会被阻挡。
总结:聚集索引不仅有提高搜索速度的好处,而且可以提高并发性。因此聚集索引的选择要
慎重!