暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle索引分裂 Index Block Split介绍

bestpaydata 2021-04-18
1600

索引分裂:index block split :就是索引块的分裂,当一次DML 事务操作修改了索引块上的数据,但是旧有的索引块没有足够的空间去容纳新修改的数据,那么将分裂出一个新的索引块,旧有块的部分数据放到新开辟的索引块上去.

分裂的类型:根节点分裂,分支节点分裂,叶节点分裂(最频繁发生,对性能影响最直接)

按照数据迁移量的比例,将索引分裂分为两种类型:9-1分裂和5-5分裂.

9-1分裂:绝大部分数据还保留在旧有节点上,仅有非常少的一部分数据迁移到新节点上。

5-5分裂:旧节点和新节点上的数据比例几乎是持平的。

5-5 分裂发生的条件:

1.左侧节点发生新值插入时(新值小于索引中的最大值)。

2.发生DML 操作,索引块上没有足够空间分配新的ITL槽。

3.新值待插入的索引上存在其他未提交的事务。

5-5分裂:


9-1分裂:通常是索引的键值是递增的,表上的事务并发量比较低,可以保证新的数据块上有较大的空闲空间插入新值。

5-5分裂:表上的事务并发度较高,操作的数据是无序的,需保证分裂的新旧数据块上有相对较大的空闲空间容纳新事务的操作。

9-1分裂如下:


对性能来说,无论9-1还是5-5 都不是什么好事。

索引结构如下:


--9-1 分裂分析

create table t_index(id number,namevarchar2(100));

create index i_index_01 on t_index(id);

alter session set events '10224trace name context forever,level 1';

declare

begin

for iin 1 .. 3000 loop

insert into t_index values (i, 'ls');

endloop;

commit;

end;

alter session set events '10224 trace namecontext off';

splitting leaf,dba0x02015f04,time 15:19:09.639

kdisnew_bseg_srch_cbk reject block -markfull,dba 0x02015f04,time 15:19:09.640

kdisnew_bseg_srch_cbk rejecting block ,dba0x02015f04,time 15:19:09.640

kdisnew_bseg_srch_cbk using block,dba0x02015f1e,time 15:19:09.640

kdisnew_bseg_srch_cbk reject block -markfull,dba 0x02015f1e,time 15:19:09.640

kdisnew_bseg_srch_cbk rejecting block ,dba0x02015f1e,time 15:19:09.640

kdisnew_bseg_srch_cbk using block,dba0x02015f22,time 15:19:09.640

splitting leaf,dba0x02015f22,time 15:19:09.676

kdisnew_bseg_srch_cbk reject block -markfull,dba 0x02015f22,time 15:19:09.676

kdisnew_bseg_srch_cbk rejecting block ,dba0x02015f22,time 15:19:09.676

kdisnew_bseg_srch_cbk using block,dba0x02015f26,time 15:19:09.676

splitting leaf,dba0x02015f26,time 15:19:09.711

kdisnew_bseg_srch_cbk reject block -markfull,dba 0x02015f26,time 15:19:09.711

kdisnew_bseg_srch_cbk rejecting block ,dba0x02015f26,time 15:19:09.711

kdisnew_bseg_srch_cbk using block,dba0x02015f2a,time 15:19:09.711

splitting leaf,dba0x02015f2a,time 15:19:09.748

kdisnew_bseg_srch_cbk reject block -markfull,dba 0x02015f2a,time 15:19:09.748

kdisnew_bseg_srch_cbk rejecting block ,dba0x02015f2a,time 15:19:09.748

kdisnew_bseg_srch_cbk using block,dba0x02015f2e,time 15:19:09.748

splitting leaf,dba0x02015f2e,time 15:19:09.784

kdisnew_bseg_srch_cbk reject block -markfull,dba 0x02015f2e,time 15:19:09.784

kdisnew_bseg_srch_cbk rejecting block ,dba0x02015f2e,time 15:19:09.784

kdisnew_bseg_srch_cbk using block,dba 0x02015f32,time15:19:09.784

--验证是否发生了9-1分裂:

SQL> select s.SID, n.NAME, s.VALUE

2 from v$sesstat s, v$statnamen

3 where s.STATISTIC# =n.STATISTIC#

4 and sid in (select sid fromv$mystat)

5 and value > 0

6 and n.NAME like '%split%'

7 ;

SID NAME VALUE

---------- ---------------------------------------------------------------- ----------

776 leaf node splits 5

776 leaf node 90-10 splits 5

记录了5次索引叶子节点数据块的分裂,也就是说整个过程发生了5次索引分裂,因为表和索引都是新建的,所以次索引树结构应该有6个叶节点数据块。

SQL> ALTER SESSION SET EVENTS 'immediatetrace name treedump level 159572';

Session altered.

*** 2015-12-22 16:19:30.295

branch: 0x2015f04 33644292 (0: nrow: 6,level: 1)

leaf: 0x2015f1e 33644318 (-1: nrow: 540 rrow: 540)

leaf: 0x2015f22 33644322 (0: nrow: 533 rrow: 533)

leaf: 0x2015f26 33644326 (1: nrow: 533 rrow: 533)

leaf: 0x2015f2a 33644330 (2: nrow: 533 rrow: 533)

leaf: 0x2015f2e 33644334 (3: nrow: 533 rrow: 533)

leaf: 0x2015f32 33644338 (4: nrow: 328 rrow: 328)

----- end tree dump

ANALYZE INDEX I_INDEX_01 VALIDATE STRUCTURE;

SQL> SELECT HEIGHT,

2 ROUND((DEL_LF_ROWS_LEN LF_ROWS_LEN) * 100, 2) || '%' RATIO,

3 PCT_USED

4 FROM INDEX_STATS

5 WHERE NAME = 'I_INDEX_01';

HEIGHT RATIO PCT_USED

--------------------------------------------------- ----------

2 0% 81

SQL> SELECT PCT_FREE FROM USER_INDEXES WHERE INDEX_NAME = 'I_INDEX_01';

PCT_FREE

----------

10

--分析i_index_01 结构:索引空间,使用率大约81% 左右,从dump文件看出,每个叶子块大约存储530 个条目,

简单的换算:81% 充盈的叶块可以存储 533 行记录,那么一个100% 充盈的块就可以存储 533/0.81 =658行记录

同时我们看到索引的PCT_FREE=10%,也就是说索引的叶块的利用率可达到90% ,单块可以存储记录行数为658 * 0.9=592

但是实际情况是单块存储记录的行数还没到达592(才530)就开始分裂了。PCT_FREE 参数的设置被忽略了。

--5-5分裂分析:

create table t_index_1(id number,namevarchar2(100));

create index i_index_02 on t_index_1(id);

alter session set events '10224 trace namecontext forever,level 1';

--反序插入3000条记录

declare

begin

for iin 1 .. 3000 loop

insert into t_index_1 values (3001-i, 'ls');

endloop;

commit;

end;

--5-5分裂会导致索引叶子节点的数据块使用率不高--(使用率不高的时候就发生了分裂)

SQL> select s.SID, n.NAME, s.VALUE

from v$sesstat s, v$statname n

where s.STATISTIC# = n.STATISTIC#

and sid in (select sid from v$mystat)

and value > 0

and n.NAME like '%split%';


SID NAME VALUE

---------- ---------------------------------------------------------------- ----------

776 leaf node splits 10

ANALYZE INDEX I_INDEX_02 VALIDATE STRUCTURE;

SQL> SELECT HEIGHT,

2 ROUND((DEL_LF_ROWS_LEN LF_ROWS_LEN) * 100, 2) || '%' RATIO,

3 PCT_USED

4 FROM INDEX_STATS

5 WHERE NAME = 'I_INDEX_02';

HEIGHT RATIO PCT_USED

---------- ---------------------------------------------------

2 0% 47

--此时索引空间总体的使用率由之前的81% 下降到47%

select object_id, object_name

fromdba_objects

whereowner = user

andobject_name = 'I_INDEX_01'

--

altersession set events 'immediate trace name treedump level 88317'

*** 2015-12-24 13:31:00.102

*** SESSION ID:(776.93) 2015-12-2413:31:00.102

*** CLIENT ID:() 2015-12-24 13:31:00.102

*** SERVICE NAME:(SYS$USERS) 2015-12-2413:31:00.102

*** MODULE NAME:(SQL*Plus) 2015-12-2413:31:00.102

*** ACTION NAME:() 2015-12-24 13:31:00.102

----- begin tree dump

branch: 0x2016004 33644548 (0: nrow: 11,level: 1)

leaf: 0x201601e 33644574 (-1: nrow: 375 rrow: 375)

leaf: 0x201600b 33644555 (0: nrow: 262 rrow: 262)

leaf: 0x2016007 33644551 (1: nrow: 262 rrow: 262)

leaf: 0x201603e 33644606 (2: nrow: 267 rrow: 267)

leaf: 0x201603a 33644602 (3: nrow: 262 rrow: 262)

leaf: 0x2016036 33644598 (4: nrow: 262 rrow: 262)

leaf: 0x2016032 33644594 (5: nrow: 262 rrow: 262)

leaf: 0x201602e 33644590 (6: nrow: 262 rrow: 262)

leaf: 0x201602a 33644586 (7: nrow: 262 rrow: 262)

leaf: 0x2016026 33644582 (8: nrow: 262 rrow: 262)

leaf: 0x2016022 33644578 (9: nrow: 262 rrow: 262)

----- end tree dump

--单块存储的记录行数由570行下降到262行。说明此时索引有点"虚胖"

导致问题:在一次简单的查询或者dml操作中,会扫描非常多的索引块,直接导致I/O次数的增加,特别是在并发度很高的表上。

5-5分裂中,PCT_FREE参数再一次被忽视。参数PCT_FREE在索引创建时起作用,而在使用时往往被忽略。

SQL> SELECT PCT_FREE FROM USER_INDEXESWHERE INDEX_NAME = 'I_INDEX_02';

PCT_FREE

----------

10

--在索引块上,以下两种情况会触发'enq: TX-allocate ITL entry' 等待:

1.达到数据块上最大事务数限制

2.递归事务ITL 争用

总结:

索引的争用源自于索引的分裂,而触发索引的分裂的契机就是索引上的高并发事务操作。

如何去解决高并发导致索引分裂的争用:

1.增加ITL槽来增加并发处理能力-->修改索引initrans 参数

其实修改initrans 参数并没有真正解决问题,随着并发度的不断提升,ITL 槽的争用也越发激烈。

2.反向建索引。利:入库高效了,几乎完全消除了enq:TX-index contention 弊:数据读取低效,本来访问一个索引块即可,现在需要访问多个索引块了。增加了额外I/O开销。


下集预告: 索引分裂的具体影响和测试分析及OLTP系统是否需要Rebuild 索引。

下下集预告:数据库行迁移和行链接。


文章转载自bestpaydata,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论