高并发索引争用问题解决方法探讨
[color=rgb(62, 62, 62)]对于sequence 生成的主键索引,高并发时会出现严重的争用情况,下面AWR的前TOP4 等待事件,都是index contention相关的等待事件,非常严重:[color=rgb(62, 62, 62)][img]http://mmbiz.qpic.cn/mmbiz_jpg/2oPp0icMGX4xGkcSTcNBjI4lzQVa4gycXtdtmrYFmuwcr8PRQLVCFAdQ9ibRVYhugGZunO4ls1naLzx4tHazOl4g/0?wx_fmt=jpeg[/img]
[color=rgb(62, 62, 62)]为什么高并发会产生索引争用?[color=rgb(62, 62, 62)] 索引争用一般在字段值顺序递增的情况下表现最为严重,比如上面的由sequence生成的主键索引,因为索引值需要顺序存放,多个并发session都在争用一个index block,导致buffer busy waits和TX- index contention。这种情况在RAC环境会更加严重:同一个block又需要在节点间传来传去,gc buffer busy acquire和gc buffer busy release就是RAC环境下多出来的等待事件。
[color=rgb(62, 62, 62)]
[color=rgb(62, 62, 62)]为什么data block没有那么严重的争用?[color=rgb(62, 62, 62)] data block没有顺序存放的要求,ASSM管理的表空间,多个session 可以插入数据到不同的 block。
[p=25, null, left][color=rgb(62, 62, 62)] 有很多文章介绍过索引争用的解决方法,大致如下:[color=rgb(62, 62, 62)]1、反向键索引[color=rgb(62, 62, 62)]2、将索引进行hash分区[p=25, null, left][color=rgb(62, 62, 62)]3、增大PCTFREE
[p=25, null, left][color=rgb(62, 62, 62)]上面几种方法都有一些缺点(下面还有性能对比图):[p=25, null, left][color=rgb(62, 62, 62)]反向键索引:表相对小的时候性能尚可,表很大的时候,TPS会下降,响应时间也会变长,而且这种索引,只支持等值查询,不支持范围查询(>=,< ,between and等都不支持)
[p=25, null, left][color=rgb(62, 62, 62)]Hash分区索引:通过hash方式将字段值分散到不同的block,在RAC环境下,虽然可以提高TPS,但是响应时间会稍稍变长。
[p=25, null, left][color=rgb(62, 62, 62)]增大PCTFREE值:会占用更多的存储空间,更重要的是会占用更多的buffer cache内存,而且对缓解索引争用的效果一般。
[p=25, null, left][color=rgb(62, 62, 62)] 针对这种情况,老虎刘原来所在的研发部门Real-World Performance(RWP)提供了一个最佳的解决方案:[p=25, null, left][color=rgb(62, 62, 62)]原来插入记录的代码:[p=25, null, left][color=rgb(62, 62, 62)]INSERT INTO log_big_clever(id,......) VALUES (big_clever_seq.nextval,......);[p=25, null, left][color=rgb(62, 62, 62)]修改后的代码:在sequence前增加前缀(称之为smart index)[p=25, null, left][color=rgb(62, 62, 62)]prefix1:=1E+23 * USERENV('INSTANCE');[p=25, null, left][color=rgb(62, 62, 62)]prefix2:=1E+20 * mod(USERENV('SID'),100);[p=25, null, left][color=rgb(62, 62, 62)]INSERT INTO log_big_clever (id,......)VALUES (prefix1+prefix2+ big_clever_seq.nextval,......);[p=25, null, left][color=rgb(62, 62, 62)] 注:本例定义的sequence的最大值为10^19-1[p=25, null, left][color=rgb(62, 62, 62)]注意红色部分代码,因为使用了instance和sid的前缀,生成的字段值就不是单纯的递增,多个并发session可以插入到多达200个不同的index block,而且这些index block也不会在RAC的节点间传来传去,避免了gc等待。可以彻底的解决index contention的问题。
[p=25, null, left][color=rgb(62, 62, 62)]下面是RWP做的一个性能对比,对应的各柱状图分别是:[p=25, null, left][color=rgb(62, 62, 62)]普通索引[p=25, null, left][color=rgb(62, 62, 62)]反向键索引-小表[p=25, null, left][color=rgb(62, 62, 62)]反向键索引-大表[p=25, null, left][color=rgb(62, 62, 62)]hash索引-大表[p=25, null, left][color=rgb(62, 62, 62)]hash索引-大表两节点RAC[p=25, null, left][color=rgb(62, 62, 62)]smart索引(索引还是普通索引,只是插入的值增加了前缀)[p=25, null, left][color=rgb(62, 62, 62)][img=0,1]http://mmbiz.qpic.cn/mmbiz_jpg/2oPp0icMGX4xGkcSTcNBjI4lzQVa4gycXtm4eLHv2sjwRFedP1IRYvsZ8rCyBtiaCpsNquU76muwDISxNqsG6upg/0?wx_fmt=jpeg[/img]
[p=25, null, left][color=rgb(62, 62, 62)]由上图对比可知,smart index的TPS最高,响应时间最低,是一种完美的解决sequence主键索引争用的方法。这种方法的缺点就是需要改代码。
[p=25, null, left][color=rgb(62, 62, 62)]如果不想改代码,那么hash index是解决索引争用的一个很好方法,此外,可以考虑:减少并发、单节点连接、增大sequence的cache size(可以增大到10000,本文第一张图AWR显示的top 5th等待事件,就是cache size小所致)、或适当增大pctfree等几种方法。