当一个事务对一个索引块做DML时,由于该索引块没有空闲空间导致索引块分裂,这时其他事务正在向这个索引块做DML时就会产生等待,直到这个索引块分裂完成。

以下是发生索引分裂竞争的几种场景:

1)通常情况下分裂一个索引块是毫秒级的,如果某个会话长时间持有锁,也就是说该会话分裂索引块时间长,那么就需要查该会话的等待事件和读取的对象,很可能是在位图块中寻找一个可用的空块而消耗了更多的时间;

2)应用程序并发数大时导致了热块竞争,通常伴随着gc类的等待一起发生;

3)在RAC环境中,由于全局缓冲块和全局队列的争用,当私网传输有性能瓶颈时会发生,比如私网流量大或者传输时有丢失的情况而导致不能快速申请到空的索引块,通常伴随着gc类的等待一起发生。


明确了发生索引分裂竞争的原因后就需要检查是哪个对象发生了等待,从AWR中确认

Segments by RowLock Waits

% of Capture shows% of row lock waits for each top segment compared

with total rowlock waits for all segments captured by the Snapshot

此外,还可以从AWR中找出是哪类的分裂

Instance Activity Stats

Ordered by statistic name

按照分裂对象分:

1)根节点分裂:特殊的枝节点分裂,分裂需要两个新的数据块,将原有数据转移至两个新节点,原有节点上生成两条记录分别指向新增的数据块

2)枝节点分裂:其下层的叶节点分裂,会导致在该节点上增加一条记录指向新加的节点,当该节点空间不足时会发生分裂

3)叶节点分裂:叶子节点上没有足够的空间容纳新插入的数据

按照分裂数据块比例分:

1)9-1分裂:通常是主键单向增长型索引,当事务向索引块的最右侧的叶节点上插入一条大于或等于现有索引块上最大值的数据

2)5-5分裂:通常是普通索引,当事务向索引块新插入数值小于索引中最大值

 

解决方法:

1)针对第一种场景,定期重建索引;

2)针对第二种场景,创建反向键索引,反向键可以消除索引分裂竞争,而它的缺点是它可能影响索引范围扫描的性能。除此之外,还可以将索引改造为HASH分区(通常分区数8个即可),目的是通过HASH算法将递增的索引键值分布到多个分区上,从而避免insert或update时索引分裂竞争;

3)针对第三种场景,如果是私网流量大就需要分析SQL是否可以优化,如果是网络有丢包现象就需要通过系统网络层分析。

 

索引分裂如何找到一个空闲的块:

Oracle的空间管理模块(元数据)会在位图块BITMAPBLOCK(L3、L2、L1)中使用五种状态来描述数据块的空间使用情况,以便当插入数据时可以从中挑选可用空块来重用(找不到再扩展),五种状态如下表示:

1)0~25% free

2)25~50% free

3)50~75% free

4)75~100% free   --块中有75%~100%的空闲空间

5)Full Blocks      --块没有任何空间,不允许充当空块

位图块里是没有一个状态是表示一个数据块是完全空块,只有"75~100% free"状态的空块。如果要插入的数据正好处于"75~100%free"大小,则将从位图块中查找一个状态是"75~100%free"的数据块,然后使用该数据块;如果要插入的数据正好处于"75~100% free",而且也寻找到一个"75~100%free"的数据块,但是因为无法将数据插入到该数据块,Oracle就会将该块的位图信息更新为full状态(尽管该块还有剩余的空间),后续插入数据就不会再来使用该数据块。


| 作者简介

管海涛·沃趣科技高级数据库工程师

熟悉Oracle数据库内部机制,丰富的数据库及RAC集群层故障诊断、性能调优、OWI、数据库备份恢复及迁移经验。





沃趣科技,让客户用上更好的数据库技术!