技术开发 频道

B-Tree 索引中的数据块分裂

  【IT168 技术文档】什么是B-tree索引块分裂

  当一个事务需要修改(大多数情况是Insert操作,某些情况下也可能为Delete操作)索引块(枝节点或叶子节点)上的数据,但没有足够空间容纳新的数据(包括索引条目、ITL slot)时,会将原有块上的部分数据放到一个新的数据块上去,这一过程就是索引块分裂(Index Block Splitting)。

  什么情况下发生索引块分裂

  按照分裂的对象不同,分为叶子节点分裂和枝节点分裂,而枝节点分裂中还有一个特殊的分裂:根节点分裂。

  按照分裂时,2个数据块上分布的数据比例,分为5-5分裂和9-1分裂:

  5-5分裂:新旧2个数据块上的数据基本相等;

  9-1分裂:大部分数据还在原有数据块上,只有少量数据被转移到新的数据块上。

  叶子节点分裂

  1、当Insert、Update(实际上就是Delete+Insert)时,叶子节点块上没有足够空间容纳新的索引条目,就会发生叶子节点分裂:

 HELLODBA.COM> create table idx_split (a number, b varchar2(1446), c date);

  
Table created.

  HELLODBA.COM
> create index idx_split_idx on idx_split (a, b) tablespace idx_2k pctfree 10;

  
Index created.

  HELLODBA.COM
> begin

  
2 for i in 1..1000

  
3 loop

  
4 insert into tx_index_contention (a, b, c) values (i, lpad('A', 10, 'A'), sysdate);

  
5 end loop;

  
6 end;

  
7 /

  PL
/SQL procedure successfully completed.

  HELLODBA.COM
> commit;

  
Commit complete.

  HELLODBA.COM
> alter session set events '10224 trace name context forever,level 1';

  Session altered.

  
--叶子节点没有足够空间,发生分裂

  HELLODBA.COM
> insert into idx_split (a, b, c) values (800, lpad('A', 20, 'A'), sysdate);

  
1 row created.

  在10224事件的trace文件中可以看到叶子节点块分裂的记录: 

splitting leaf,dba 0x03c00557,time 12:44:01.652

  kdisnew_bseg_srch_cbk reject block
-mark full,dba 0x03c0054a,time 12:44:01.699

  kdisnew_bseg_srch_cbk rejecting block ,dba
0x03c0054a,time 12:44:01.699

  kdisnew_bseg_srch_cbk using block,dba
0x03c0054b,time 12:44:01.699

  同时,将Btree结构dump出来,也可以看到节点被分裂:

 HELLODBA.COM> alter session set events 'immediate trace name treedump level 198801';

  Session altered.

  Trace文件:

  leaf:
0x3c00557 62915927 (14: nrow: 31 rrow: 31)

  leaf:
0x3c0054b 62915915 (15: nrow: 21 rrow: 21)

  2、当事务需要修改节点上的数据,叶子节点上没有足够空间容纳新的ITL slot时,也会发生分裂。

  我们dump出一个“满”的节点,注意到它上面的空闲空间只有20字节,小于一条ITL slot的大小(24字节)

Block header dump: 0x03c00551

  Object id
on Block? Y

  seg
/obj: 0x30892 csc: 0x00.b10c56ed itc: 2 flg: E typ: 2 - INDEX

  brn:
0 bdba: 0x3c00542 ver: 0x01 opc: 0

  inc:
0 exflg: 0

  Itl Xid Uba Flag Lck Scn
/Fsc

  
0x01 0x00b0.01d.00000009 0x00800b1e.0021.02 -BU- 1 fsc 0x0000.b10c56f0

  
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000

  ...

  kdxconro
51

  kdxcofbo
138=0x8a

  kdxcofeo
158=0x9e

  kdxcoavs
20

  ...

  并且此时它里面有一条空闲ITL slot(第一条ITL slot是用于递归事务的,后面会有解释),先用一个事务占用它: 

HELLODBA.COM> delete from idx_split where a=500;

  
1 row deleted.

  然后再启动一个事务,造成了空间不足分配新的ITL slot,而导致节点分裂:

 HELLODBA.COM> alter session set events '10224 trace name context forever,level 1';

  Session altered.

  HELLODBA.COM
> delete from idx_split where a=501;

  
1 row deleted.

  在10224trace文件中记录此次分裂:

splitting leaf,dba 0x03c00551,time 12:54:00.827

  kdisnew_bseg_srch_cbk using block,dba
0x03c00550,time 12:54:00.874
0
相关文章