HelloDBA [English]
搜索Internet 搜索 HelloDBABA
  Oracle技术站。email: fuyuncat@gmail.com  MSN: fuyuncat@hotmail.com   acoug  acoug 

B*Tree 索引中的数据块分裂——存储参数

[English]

作者: fuyuncat

来源: www.HelloDBA.com

日期: 2009-10-14 06:54:17

分享到  新浪微博 腾讯微博 人人网 i贴吧 开心网 豆瓣 淘宝 推特 Facebook GMail Blogger Orkut Google Bookmarks

    我们知道,在表的数据块中,当数据插入时,要保证数据块上剩余空间大于、等于PCTFREE的比例设置,以用于数据更新和多事务处理,从而减少数据迁移(Row Migration)的发生;而当分配新的数据块时,会根据INITRANS的设置预留相应的ITL slot,保证并发事务能分配到ITL slot。

    在索引中,这两个参数仅在有数据时创建或重建索引才会起作用,且仅在叶子节点上起作用。

INITRANS

    INITRANS在索引数据块上是否起作用,是由索引在创建或重建时是否有数据(即是否会分配数据块)决定的。比较以下代码,第一段代码在truncate之后rebuild(即不会分配索引数据块),因而ITL slot数量为默认值2;第二段代码在有数据时rebuild,然后再truncate,此时再插入数据产生的新的索引块上ITL slot数量就受到INITRANS的控制:

SQL代码
  1. --代码1:   
  2. HELLODBA.COM> truncate table idx_split;   
  3.   
  4. Table truncated.   
  5.   
  6. HELLODBA.COM> alter index idx_split_idx rebuild initrans 3 pctfree 10;   
  7.   
  8. Index altered.   
  9.   
  10. HELLODBA.COM> begin  
  11.   2     for i in 1..35   
  12.   3     loop   
  13.   4         insert into idx_split (a, b, c) values (i*3, lpad('A', 100, 'A'), sysdate);   
  14.   5     end loop;   
  15.   6  end;   
  16.   7  /   
  17.   
  18. PL/SQL procedure successfully completed.   
  19.   
  20. HELLODBA.COM> commit;   
  21.   
  22. Commit complete.   
  23.   
  24. HELLODBA.COM> alter session set events 'immediate trace name treedump level 199127';   
  25.   
  26. Session altered.   
  27.   
  28. --代码2:   
  29. HELLODBA.COM> truncate table idx_split;   
  30.   
  31. Table truncated.   
  32.   
  33. HELLODBA.COM> insert into idx_split (a, b, c) values (1*3, lpad('A', 100, 'A'), sysdate);   
  34.   
  35. 1 row created.   
  36.   
  37. HELLODBA.COM> commit;   
  38.   
  39. Commit complete.   
  40.   
  41. HELLODBA.COM> alter index idx_split_idx rebuild initrans 3 pctfree 10;   
  42.   
  43. Index altered.   
  44.   
  45. HELLODBA.COM> truncate table idx_split;   
  46.   
  47. Table truncated.   
  48.   
  49. HELLODBA.COM> begin  
  50.   2     for i in 1..35   
  51.   3     loop   
  52.   4         insert into idx_split (a, b, c) values (i*3, lpad('A', 100, 'A'), sysdate);   
  53.   5     end loop;   
  54.   6  end;   
  55.   7  /   
  56.   
  57. PL/SQL procedure successfully completed.   
  58.   
  59. HELLODBA.COM> alter session set events 'immediate trace name treedump level 199127';   
  60.   
  61. Session altered.  

    需要注意的是,当数据块上ITL Slot数量大于起作用的INITRANS时,在分裂时被“继承”。在以下例子中,在rebuild时,指定了INITRANS为3:

SQL代码
  1. HELLODBA.COM> truncate table idx_split;   
  2.   
  3. Table truncated.   
  4.   
  5. HELLODBA.COM> conn demo/demo   
  6. Connected.   
  7. HELLODBA.COM> alter session set events '10224 trace name context forever,level 1';   
  8.   
  9. Session altered.   
  10.   
  11. HELLODBA.COM> begin  
  12.   2     for i in 1..100   
  13.   3     loop   
  14.   4         insert into idx_split (a, b, c) values (i*3, lpad('A', 100, 'A'), sysdate);   
  15.   5     end loop;   
  16.   6  end;   
  17.   7  /   
  18.   
  19. PL/SQL procedure successfully completed.   
  20.   
  21. HELLODBA.COM> commit;   
  22.   
  23. Commit complete.   
  24.   
  25. HELLODBA.COM> alter index idx_split_idx rebuild initrans 3 pctfree 60;   
  26.   
  27. Index altered.   
  28.   
  29. HELLODBA.COM> alter session set events 'immediate trace name treedump level 199127';   
  30.   
  31. Session altered.  

    我们同时启动4个事务作用在最后一个节点,导致该数据块上分配5个(加一个递归事务ITL slot)ITL slot:

SQL代码
  1. -- Trans 1   
  2. HELLODBA.COM> delete from idx_split where a=100*3;   
  3.   
  4. 1 row deleted.   
  5.   
  6. -- Trans 2   
  7. HELLODBA.COM> delete from idx_split where a=99*3;   
  8.   
  9. 1 row deleted.   
  10.   
  11. --Trans 3   
  12. HELLODBA.COM> delete from idx_split where a=98*3;   
  13.   
  14. 1 row deleted.   
  15.   
  16. --Trans 4   
  17. HELLODBA.COM> delete from idx_split where a=97*3;   
  18.   
  19. 1 row deleted.  

    然后将它们全部提交或回滚,再插入数据,造成分裂:

SQL代码
  1. --9-1分裂   
  2. HELLODBA.COM> begin  
  3.   2     for i in 101..150   
  4.   3     loop   
  5.   4         insert into idx_split (a, b, c) values (i*3, lpad('A', 100, 'A'), sysdate);   
  6.   5     end loop;   
  7.   6  end;   
  8.   7  /   
  9.   
  10. PL/SQL procedure successfully completed.   
  11.   
  12. HELLODBA.COM> alter session set events 'immediate trace name treedump level 199127';   
  13.   
  14. Session altered.   
  15.   
  16. --5-5分裂   
  17. HELLODBA.COM> insert into idx_split (a, b, c) values (138*3, lpad('A', 100, 'A'), sysdate);   
  18.   
  19. 1 row created.   
  20.   
  21. HELLODBA.COM> alter session set events 'immediate trace name treedump level 199127';   
  22.   
  23. Session altered.  

    Dump出分裂的数据块,可以看到所有数据块都被分配了5个ITL slot,而不是INITRANS(3)的数量:

SQL代码
  1. Block header dump:  0x03c0041d   
  2.  Object id on Block? Y   
  3.  seg/obj: 0x30a50  csc: 0x00.b1859616  itc: 5  flg: E  typ: 2 - INDEX  
  4.      brn: 0  bdba: 0x3c00402 ver: 0x01 opc: 0   
  5.      inc: 0  exflg: 0   
  6.     
  7.  Itl           Xid                  Uba         Flag  Lck        Scn/Fsc   
  8. 0x01   0x005f.016.00000256  0x008019b5.0120.02  -B--    1  fsc 0x0000.00000000   
  9. 0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000   
  10. 0x03   0x005f.005.00000257  0x008019b4.0120.27  ----    5  fsc 0x0000.00000000   
  11. 0x04   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000   
  12. 0x05   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000  

PCTFREE

    PCTFREE在分裂时则被忽略。在上述例子中,我们找到一块发生9-1分裂产生的数据块,可以看到其空闲空间为44b,空闲率为44/2048=2.1%,远远小于我们rebuild时的设定值(60)。

SQL代码
  1. ...
  2. kdxcofbo 66=0x42   
  3. kdxcofeo 110=0x6e   
  4. kdxcoavs 44  
  5. ...

    我们再插入一些中间数据,造成5-5分裂:

SQL代码
  1. HELLODBA.COM> begin  
  2.   2     for i in 1..15   
  3.   3     loop   
  4.   4         insert into idx_split (a, b, c) values (50*3, lpad('A', 100, 'A'), sysdate);   
  5.   5     end loop;   
  6.   6  end;   
  7.   7  /   
  8.   
  9. PL/SQL procedure successfully completed.   
  10.   
  11. HELLODBA.COM> alter session set events 'immediate trace name treedump level 199127';   
  12.   
  13. Session altered.  

    可以看到,发生分裂的数据块的空闲率为556/2048=27.1%,可见PCTFREE(60)也被忽略了。

SQL代码
  1. ...   
  2. kdxcofbo 58=0x3a   
  3. kdxcofeo 614=0x266   
  4. kdxcoavs 556   
  5. ...  
 

    --- Fuyuncat TBC ---

Top

Copyright ©2005,HelloDBA.Com 保留一切权利

申明
by fuyuncat