Oracle索引分裂(Index Block Split)

lhrbest發表於2017-05-17

Oracle索引分裂(Index Block Split)



索引分裂: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,name varchar2(100));

create index i_index_01 on t_index(id);


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


declare

begin

  for i in 1 .. 3000 loop

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

  end loop;

  commit;

end;


alter session set events '10224 trace name context off';


splitting leaf,dba 0x02015f04,time 15:19:09.639           

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

kdisnew_bseg_srch_cbk rejecting block ,dba 0x02015f04,time 15:19:09.640

kdisnew_bseg_srch_cbk using block,dba 0x02015f1e,time 15:19:09.640

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

kdisnew_bseg_srch_cbk rejecting block ,dba 0x02015f1e,time 15:19:09.640

kdisnew_bseg_srch_cbk using block,dba 0x02015f22,time 15:19:09.640

splitting leaf,dba 0x02015f22,time 15:19:09.676                 

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

kdisnew_bseg_srch_cbk rejecting block ,dba 0x02015f22,time 15:19:09.676

kdisnew_bseg_srch_cbk using block,dba 0x02015f26,time 15:19:09.676

splitting leaf,dba 0x02015f26,time 15:19:09.711               

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

kdisnew_bseg_srch_cbk rejecting block ,dba 0x02015f26,time 15:19:09.711

kdisnew_bseg_srch_cbk using block,dba 0x02015f2a,time 15:19:09.711

splitting leaf,dba 0x02015f2a,time 15:19:09.748                         

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

kdisnew_bseg_srch_cbk rejecting block ,dba 0x02015f2a,time 15:19:09.748

kdisnew_bseg_srch_cbk using block,dba 0x02015f2e,time 15:19:09.748

splitting leaf,dba 0x02015f2e,time 15:19:09.784                 

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

kdisnew_bseg_srch_cbk rejecting block ,dba 0x02015f2e,time 15:19:09.784

kdisnew_bseg_srch_cbk using block,dba 0x02015f32,time 15:19:09.784


--驗證是否發生了9-1分裂:

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

  2    from v$sesstat s, v$statname n

  3   where s.STATISTIC# = n.STATISTIC#

  4     and sid in (select sid from v$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 'immediate trace 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,name varchar2(100));

create index i_index_02 on t_index_1(id);


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

--反序插入3000條記錄

declare

begin

  for i in 1 .. 3000 loop

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

  end loop;

  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

  from dba_objects

 where owner = user

   and object_name = 'I_INDEX_01'

--


 alter session set events 'immediate trace name treedump level 88317'



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

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

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

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

*** MODULE NAME:(SQL*Plus) 2015-12-24 13: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_INDEXES WHERE 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開銷。







About Me

...............................................................................................................................

● 本文整理自網路

● 本文在itpub(http://blog.itpub.net/26736162)、部落格園(http://www.cnblogs.com/lhrbest)和個人微信公眾號(xiaomaimiaolhr)上有同步更新

● 本文itpub地址:http://blog.itpub.net/26736162/abstract/1/

● 本文部落格園地址:http://www.cnblogs.com/lhrbest

● 本文pdf版及小麥苗雲盤地址:http://blog.itpub.net/26736162/viewspace-1624453/

● 資料庫筆試面試題庫及解答:http://blog.itpub.net/26736162/viewspace-2134706/

● QQ群:230161599     微信群:私聊

● 聯絡我請加QQ好友(646634621),註明新增緣由

● 於 2017-05-09 09:00 ~ 2017-05-30 22:00 在魔都完成

● 文章內容來源於小麥苗的學習筆記,部分整理自網路,若有侵權或不當之處還請諒解

● 版權所有,歡迎分享本文,轉載請保留出處

...............................................................................................................................

拿起手機使用微信客戶端掃描下邊的左邊圖片來關注小麥苗的微信公眾號:xiaomaimiaolhr,掃描右邊的二維碼加入小麥苗的QQ群,學習最實用的資料庫技術。

Oracle索引分裂(Index Block Split)
DBA筆試面試講解
歡迎與我聯絡

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26736162/viewspace-2139232/,如需轉載,請註明出處,否則將追究法律責任。

相關文章