键值重复率高的B树索引构建过程和查询操作分析

 


                                

                                  liuyu(2014-09-16)

 

 

创建测试表:

SQL> create table t_liu(id number,namevarchar2(100));

Table created.

 

SQL> createindex i_liu on t_liu(id);

 

 

SQL> selectobject_id from dba_objects where object_name=’I_LIU’;

 

 OBJECT_ID

———-

   150956

Index created.

—插入10条数据—-

begin

for i in 1 .. 10 loop

insert into t_liu values(i,’xxx’);

commit;

end loop;

end;

/

SQL> altersession set events ‘immediate trace name treedump level 150956’;

 

使用下面的脚本查看trc文件的位置:

 SELECT    d.VALUE

  || ‘/’

  || LOWER (RTRIM (i.INSTANCE, CHR (0)))

  || ‘_ora_’

 || p.spid

 || ‘.trc’ trace_file_name

  FROM (SELECT p.spid

  FROM SYS.v_$mystat m,SYS.v_$session s, SYS.v_$process p

  WHERE m.statistic# =1 AND s.SID = m.SID AND p.addr = s.paddr) p,

  (SELECT t.INSTANCE

  FROM SYS.v_$thread t,SYS.v_$parameter v

  WHERE v.NAME =’thread’

  AND (v.VALUE = 0 ORt.thread# = TO_NUMBER (v.VALUE))) i,

  (SELECT VALUE

  FROM SYS.v_$parameter

  WHERE NAME = ‘user_dump_dest’)d ;

 

/u01/oracle/diag/rdbms/test/test/trace/test_ora_32698.trc

 

—– begin tree dump

leaf: 0x1077233 17265203 (0: nrow: 10 rrow:10)

—– end tree dump

 

    这里发现只有一个叶子节点,因为数据只有10条,rootbranch,和leaf,只存在一个leaf块内

 

begin

for i in 1 .. 1000 loop

insert into t_liu values(i,’xxx’);

commit;

end loop;

end;

/

此时的索引已经分裂:

 

*** 2014-09-16 10:02:38.266

branch: 0x1077233 17265203 (0: nrow: 2,level: 1)

  leaf: 0x1077236 17265206 (-1: nrow: 540 rrow: 540)

  leaf: 0x1077237 17265207 (0: nrow: 470 rrow: 470)

—– end tree dump

 

 

这里测试,往里面插入最大值1000

begin

for i in 1 .. 10000 loop

insert into t_liu values(1000,’xxx’);

commit;

end loop;

end;

/

 

—– begin tree dump

branch: 0x1077233 17265203 (0: nrow: 29,level: 1)

  leaf: 0x1077236 17265206 (-1: nrow: 540 rrow: 540)

  leaf: 0x1077237 17265207 (0: nrow: 269 rrow: 269)

  leaf: 0x1077256 17265238 (1: nrow: 277 rrow: 277)

  leaf: 0x1077257 17265239 (2: nrow: 291 rrow: 291)

  leaf: 0x1077250 17265232 (3: nrow: 291 rrow: 291)

  leaf: 0x1077251 17265233 (4: nrow: 291 rrow: 291)

  leaf: 0x1077252 17265234 (5: nrow: 328 rrow: 328)

  leaf: 0x1077234 17265204 (6: nrow: 571 rrow: 571)

  leaf: 0x1077235 17265205 (7: nrow: 291 rrow: 291)

  leaf: 0x1077262 17265250 (8: nrow: 291 rrow: 291)

  leaf: 0x1077263 17265251 (9: nrow: 291 rrow: 291)

  leaf: 0x1077269 17265257 (10: nrow: 291 rrow: 291)

  leaf: 0x107726a 17265258 (11: nrow: 314 rrow: 314)

  leaf: 0x1077264 17265252 (12: nrow: 291 rrow: 291)

  leaf: 0x1077265 17265253 (13: nrow: 291 rrow: 291)

  leaf: 0x1077266 17265254 (14: nrow: 291 rrow: 291)

  leaf: 0x1077267 17265255 (15: nrow: 291 rrow: 291)

  leaf: 0x1077261 17265249 (16: nrow: 291 rrow: 291)

  leaf: 0x107726e 17265262 (17: nrow: 291 rrow: 291)

  leaf: 0x107726f 17265263 (18: nrow: 291 rrow: 291)

  leaf: 0x1077268 17265256 (19: nrow: 405 rrow: 405)

  leaf: 0x1077255 17265237 (20: nrow: 281 rrow: 281)

  leaf: 0x1077253 17265235 (21: nrow: 571 rrow: 571)

  leaf: 0x1077254 17265236 (22: nrow: 571 rrow: 571)

  leaf: 0x107726b 17265259 (23: nrow: 571 rrow: 571)

  leaf: 0x107726c 17265260 (24: nrow: 571 rrow: 571)

  leaf: 0x107726d 17265261 (25: nrow: 571 rrow: 571)

  leaf: 0x107727a 17265274 (26: nrow: 571 rrow: 571)

  leaf: 0x107727b 17265275 (27: nrow: 525 rrow: 525)

—– end tree dump

 

解释trc文件

               每一行第一列表示:节点类型,branch是分支节点(包括了根节点),而leaf则是叶子节点

               第二列表示:节点地址,16进制

               第三列表示:节点地址,10进制

               第四列表示:相对于前一个节点的位置:根节点从0算起,其他分支节点和叶子节点从1开始算

               第五列表示:(nrow)当前节点所含索引条目的数量(包括delete的条目)

               第六列表示:(level)分支节点的层级,在oracle的索引中,层级号是倒过来的,也就是说假设某个索引有N层,则根节点的层级号为N,而根节点下一层的分支节点的层级号为N-1

               第七列表示:(rrow)有效的索引条目的数量,因为索引条目如果被删除,不会立即被清除出索引块中。所以nrowrrow的数量就表示已经被删除的索引条目数量

 

begin

for i in 1 .. 400 loop

insert into t_liu values(1000,’xxx’);

commit;

end loop;

end;

/

 

*** 2014-09-16 10:18:04.906

branch: 0x1077233 17265203 (0: nrow: 32,level: 1)

  leaf: 0x1077236 17265206 (-1: nrow: 540 rrow: 540)

  leaf: 0x1077237 17265207 (0: nrow: 269 rrow: 269)

  leaf: 0x1077256 17265238 (1: nrow: 277 rrow: 277)

  leaf: 0x1077257 17265239 (2: nrow: 291 rrow: 291)

  leaf: 0x1077250 17265232 (3: nrow: 291 rrow: 291)

  leaf: 0x1077251 17265233 (4: nrow: 291 rrow: 291)

  leaf: 0x1077252 17265234 (5: nrow: 328 rrow: 328)

  leaf: 0x1077234 17265204 (6: nrow: 571 rrow: 571)

  leaf: 0x1077235 17265205 (7: nrow: 291 rrow: 291)

  leaf: 0x1077262 17265250 (8: nrow: 291 rrow: 291)

  leaf: 0x1077263 17265251 (9: nrow: 291 rrow: 291)

  leaf: 0x1077269 17265257 (10: nrow: 291 rrow: 291)

  leaf: 0x107726a 17265258 (11: nrow: 314 rrow: 314)

  leaf: 0x1077264 17265252 (12: nrow: 291 rrow: 291)

  leaf: 0x1077265 17265253 (13: nrow: 291 rrow: 291)

  leaf: 0x1077266 17265254 (14: nrow: 291 rrow: 291)

  leaf: 0x1077267 17265255 (15: nrow: 291 rrow: 291)

  leaf: 0x1077261 17265249 (16: nrow: 291 rrow: 291)

  leaf: 0x107726e 17265262 (17: nrow: 291 rrow: 291)

  leaf: 0x107726f 17265263 (18: nrow: 291 rrow: 291)

  leaf: 0x1077268 17265256 (19: nrow: 405 rrow: 405)

  leaf: 0x1077255 17265237 (20: nrow: 281 rrow: 281)

   leaf: 0x1077253 17265235 (21: nrow: 571 rrow:571)

  leaf: 0x1077254 17265236 (22: nrow: 291 rrow: 291)

  leaf: 0x107727e 17265278 (23: nrow: 289 rrow: 289)

  leaf: 0x107727d 17265277 (24: nrow: 281 rrow: 281)

  leaf: 0x107726b 17265259 (25: nrow: 571 rrow: 571)

  leaf: 0x107726c 17265260 (26: nrow: 571 rrow: 571)

  leaf: 0x107726d 17265261 (27: nrow: 571 rrow: 571)

  leaf: 0x107727a 17265274 (28: nrow: 571 rrow: 571)

  leaf: 0x107727b 17265275 (29: nrow: 571 rrow: 571)

  leaf: 0x107727c 17265276 (30: nrow: 364 rrow: 364)

 

 

这里又发生了5-5分裂。

观察下来,插入最大的重复值,9-15-5分裂都会发生。

下面测试插入当中的值

begin

for i in 1 .. 1000 loop

insert into t_liu values(500,’xxx’);

commit;

end loop;

end;

/

 

 

*** 2014-09-16 10:26:29.515

—– begin tree dump

branch: 0x1077233 17265203 (0: nrow: 36,level: 1)

  leaf: 0x1077236 17265206 (-1: nrow: 279 rrow: 279)

  leaf: 0x107727f 17265279 (0: nrow: 275 rrow: 275)

  leaf: 0x1077279 17265273 (1: nrow: 291 rrow: 291)

  leaf: 0x1078a8e 17271438 (2: nrow: 291 rrow: 291)

  leaf: 0x1078a8f 17271439 (3: nrow: 404 rrow: 404)

  leaf: 0x1077237 17265207 (4: nrow: 269 rrow: 269)

  leaf: 0x1077256 17265238 (5: nrow: 277 rrow: 277)

  leaf: 0x1077257 17265239 (6: nrow: 291 rrow: 291)

  leaf: 0x1077250 17265232 (7: nrow: 291 rrow: 291)

  leaf: 0x1077251 17265233 (8: nrow: 291 rrow: 291)

  leaf: 0x1077252 17265234 (9: nrow: 328 rrow: 328)

  leaf: 0x1077234 17265204 (10: nrow: 571 rrow: 571)

  leaf: 0x1077235 17265205 (11: nrow: 291 rrow: 291)

  leaf: 0x1077262 17265250 (12: nrow: 291 rrow: 291)

   leaf: 0x1077263 17265251 (13: nrow: 291 rrow:291)

  leaf: 0x1077269 17265257 (14: nrow: 291 rrow: 291)

  leaf: 0x107726a 17265258 (15: nrow: 314 rrow: 314)

  leaf: 0x1077264 17265252 (16: nrow: 291 rrow: 291)

  leaf: 0x1077265 17265253 (17: nrow: 291 rrow: 291)

  leaf: 0x1077266 17265254 (18: nrow: 291 rrow: 291)

  leaf: 0x1077267 17265255 (19: nrow: 291 rrow: 291)

  leaf: 0x1077261 17265249 (20: nrow: 291 rrow: 291)

  leaf: 0x107726e 17265262 (21: nrow: 291 rrow: 291)

  leaf: 0x107726f 17265263 (22: nrow: 291 rrow: 291)

  leaf: 0x1077268 17265256 (23: nrow: 405 rrow: 405)

  leaf: 0x1077255 17265237 (24: nrow: 281 rrow: 281)

  leaf: 0x1077253 17265235 (25: nrow: 571 rrow: 571)

  leaf: 0x1077254 17265236 (26: nrow: 291 rrow: 291)

  leaf: 0x107727e 17265278 (27: nrow: 289 rrow: 289)

  leaf: 0x107727d 17265277 (28: nrow: 281 rrow: 281)

  leaf: 0x107726b 17265259 (29: nrow: 571 rrow: 571)

  leaf: 0x107726c 17265260 (30: nrow: 571 rrow: 571)

  leaf: 0x107726d 17265261 (31: nrow: 571 rrow: 571)

  leaf: 0x107727a 17265274 (32: nrow: 571 rrow: 571)

  leaf: 0x107727b 17265275 (33: nrow: 571 rrow: 571)

  leaf: 0x107727c 17265276 (34: nrow: 364 rrow: 364)

—– end tree dump

 

50-50分裂:

产生的条件:

1、插入的行需要记录到本索引块

2、而本索引块中没有足够空间

3、且新插入的行不大于本索引中的所有记录。

分裂过程:

1、新申请一个新的索引块

2、将原索引块中较大的部分数据转移到新索引块中

3、将新值插入合适的索引块中

4、更新上级索引块(Branch Block

 

测试插入递增的最大值:

 

begin

for i in 1001 .. 1700 loop

insert into t_liu values(i,’xxx’);

commit;

end loop;

end;

/

 

 

*** 2014-09-16 10:31:35.229

—– begin tree dump

branch: 0x1077233 17265203 (0: nrow: 37,level: 1)

  leaf: 0x1077236 17265206 (-1: nrow: 279 rrow: 279)

  leaf: 0x107727f 17265279 (0: nrow: 275 rrow: 275)

  leaf: 0x1077279 17265273 (1: nrow: 291 rrow: 291)

  leaf: 0x1078a8e 17271438 (2: nrow: 291 rrow: 291)

  leaf: 0x1078a8f 17271439 (3: nrow: 404 rrow: 404)

  leaf: 0x1077237 17265207 (4: nrow: 269 rrow: 269)

  leaf: 0x1077256 17265238 (5: nrow: 277 rrow: 277)

  leaf: 0x1077257 17265239 (6: nrow: 291 rrow: 291)

  leaf: 0x1077250 17265232 (7: nrow: 291 rrow: 291)

   leaf: 0x1077251 17265233 (8: nrow: 291 rrow:291)

  leaf: 0x1077252 17265234 (9: nrow: 328 rrow: 328)

  leaf: 0x1077234 17265204 (10: nrow: 571 rrow: 571)

  leaf: 0x1077235 17265205 (11: nrow: 291 rrow: 291)

  leaf: 0x1077262 17265250 (12: nrow: 291 rrow: 291)

  leaf: 0x1077263 17265251 (13: nrow: 291 rrow: 291)

  leaf: 0x1077269 17265257 (14: nrow: 291 rrow: 291)

  leaf: 0x107726a 17265258 (15: nrow: 314 rrow: 314)

  leaf: 0x1077264 17265252 (16: nrow: 291 rrow: 291)

  leaf: 0x1077265 17265253 (17: nrow: 291 rrow: 291)

  leaf: 0x1077266 17265254 (18: nrow: 291 rrow: 291)

  leaf: 0x1077267 17265255 (19: nrow: 291 rrow: 291)

  leaf: 0x1077261 17265249 (20: nrow: 291 rrow: 291)

  leaf: 0x107726e 17265262 (21: nrow: 291 rrow: 291)

  leaf: 0x107726f 17265263 (22: nrow: 291 rrow: 291)

  leaf: 0x1077268 17265256 (23: nrow: 405 rrow: 405)

  leaf: 0x1077255 17265237 (24: nrow: 281 rrow: 281)

  leaf: 0x1077253 17265235 (25: nrow: 571 rrow: 571)

  leaf: 0x1077254 17265236 (26: nrow: 291 rrow: 291)

   leaf: 0x107727e 17265278 (27: nrow: 289 rrow:289)

  leaf: 0x107727d 17265277 (28: nrow: 281 rrow: 281)

  leaf: 0x107726b 17265259 (29: nrow: 571 rrow: 571)

  leaf: 0x107726c 17265260 (30: nrow: 571 rrow: 571)

  leaf: 0x107726d 17265261 (31: nrow: 571 rrow: 571)

  leaf: 0x107727a 17265274 (32: nrow: 571 rrow: 571)

  leaf: 0x107727b 17265275 (33: nrow: 571 rrow: 571)

  leaf: 0x107727c 17265276 (34: nrow: 557 rrow: 557)

  leaf: 0x1078a88 17271432 (35: nrow: 507 rrow: 507)

—– end tree dump

*** 2014-09-16 10:32:26.132

—– begin tree dump

branch: 0x1077233 17265203 (0: nrow: 44,level: 1)

  leaf: 0x1077236 17265206 (-1: nrow: 279 rrow: 279)

  leaf: 0x107727f 17265279 (0: nrow: 275 rrow: 275)

  leaf: 0x1077279 17265273 (1: nrow: 291 rrow: 291)

   leaf:0x1078a8e 17271438 (2: nrow: 291 rrow: 291)

  leaf: 0x1078a8f 17271439 (3: nrow: 404 rrow: 404)

  leaf: 0x1077237 17265207 (4: nrow: 269 rrow: 269)

  leaf: 0x1077256 17265238 (5: nrow: 277 rrow: 277)

  leaf: 0x1077257 17265239 (6: nrow: 291 rrow: 291)

  leaf: 0x1077250 17265232 (7: nrow: 291 rrow: 291)

  leaf: 0x1077251 17265233 (8: nrow: 291 rrow: 291)

  leaf: 0x1077252 17265234 (9: nrow: 328 rrow: 328)

  leaf: 0x1077234 17265204 (10: nrow: 571 rrow: 571)

  leaf: 0x1077235 17265205 (11: nrow: 291 rrow: 291)

  leaf: 0x1077262 17265250 (12: nrow: 291 rrow: 291)

  leaf: 0x1077263 17265251 (13: nrow: 291 rrow: 291)

  leaf: 0x1077269 17265257 (14: nrow: 291 rrow: 291)

  leaf: 0x107726a 17265258 (15: nrow: 314 rrow: 314)

  leaf: 0x1077264 17265252 (16: nrow: 291 rrow: 291)

  leaf: 0x1077265 17265253 (17: nrow: 291 rrow: 291)

  leaf: 0x1077266 17265254 (18: nrow: 291 rrow: 291)

  leaf: 0x1077267 17265255 (19: nrow: 291 rrow: 291)

  leaf: 0x1077261 17265249 (20: nrow: 291 rrow: 291)

  leaf: 0x107726e 17265262 (21: nrow: 291 rrow: 291)

  leaf: 0x107726f 17265263 (22: nrow: 291 rrow: 291)

  leaf: 0x1077268 17265256 (23: nrow: 405 rrow: 405)

  leaf: 0x1077255 17265237 (24: nrow: 281 rrow: 281)

  leaf: 0x1077253 17265235 (25: nrow: 571 rrow: 571)

  leaf: 0x1077254 17265236 (26: nrow: 291 rrow: 291)

  leaf: 0x107727e 17265278 (27: nrow: 289 rrow: 289)

  leaf: 0x107727d 17265277 (28: nrow: 281 rrow: 281)

  leaf: 0x107726b 17265259 (29: nrow: 571 rrow: 571)

  leaf: 0x107726c 17265260 (30: nrow: 571 rrow: 571)

  leaf: 0x107726d 17265261 (31: nrow: 571 rrow: 571)

  leaf: 0x107727a 17265274 (32: nrow: 571 rrow: 571)

  leaf: 0x107727b 17265275 (33: nrow: 571 rrow: 571)

  leaf: 0x107727c 17265276 (34: nrow: 557 rrow: 557)

  leaf: 0x1078a88 17271432 (35: nrow: 533 rrow: 533)

  leaf: 0x1078a8a 17271434 (36: nrow: 533 rrow: 533)

  leaf: 0x1078a8b 17271435 (37: nrow: 533 rrow: 533)

  leaf: 0x1078a8c 17271436 (38: nrow: 533 rrow: 533)

  leaf: 0x1078a8d 17271437 (39: nrow: 533 rrow: 533)

  leaf: 0x1078a89 17271433 (40: nrow: 533 rrow: 533)

  leaf: 0x1078a92 17271442 (41: nrow: 533 rrow: 533)

  leaf: 0x1078a93 17271443 (42: nrow: 76 rrow: 76)

 

发现全部都是9-1分裂

 

90-10分裂:

产生的条件:

1、插入的行需要记录到本索引块

2、本索引块中没有足够空间

3、新插入的行大于本索引块中的所有记录。

分裂的过程:

1、申请一个新索引块

2、将所有原索引块中的数据保留在原索引块中

3、将新的行记录插入到新申请的索引块中

4、更新上级索引块(Branch Block

 

 

 

下面测试继续插入20000个1000的值:

begin

for i in 1 .. 20000 loop

insert into t_liu values(1000,’xxx’);

commit;

end loop;

end;

/

 

 

这时,

SQL> select * from t_liu where id=1000;

30701 rows selected.

Execution Plan

———————————————————-

Plan hashvalue: 282913187

——————————————————————————–

—–

| Id | Operation | Name | Rows | Bytes |Cost (%CPU)| Time

    |

——————————————————————————–

—–

| 0 | SELECT STATEMENT | | 1 | 7 | 2 (0)|00:00

:01 |

| 1 | TABLE ACCESS BY INDEX ROWID| T_LIU |1 | 7 | 2 (0)| 00:00

:01 |

|* 2 | INDEX RANGE SCAN | I_LIU | 1 | | 1(0)| 00:00

:01 |

——————————————————————————–

—–

Predicate Information (identified byoperation id):

—————————————————

   2- access(“ID”=1000)

Statistics

———————————————————-

         0 recursive calls

         0 db block gets

      4236 consistent gets

         0 physical reads

         0 redo size

    749600 bytes sent via SQL*Net to client

     23030 bytes received via SQL*Net from client

      2048 SQL*Net roundtrips to/from client

         0 sorts (memory)

         0 sorts (disk)

     30701 rows processed

 

 

收集索引的统计信息,这时会走正确的执行计划

SQL> analyze index I_LIU computestatistics;

Index analyzed.

SQL> select * from t_liu where id=1000;

30701 rows selected.

Execution Plan

———————————————————-

Plan hashvalue: 1782896700

—————————————————————————

| Id | Operation | Name | Rows | Bytes |Cost (%CPU)| Time |

—————————————————————————

| 0 | SELECT STATEMENT | | 1 | 7 | 3 (0)|00:00:01 |

|* 1 | TABLEACCESS FULL| T_LIU | 1 | 7 | 3 (0)| 00:00:01 |

—————————————————————————

Predicate Information (identified byoperation id):

—————————————————

   1- filter(“ID”=1000)

Statistics

———————————————————-

         3 recursive calls

         0 db block gets

      2112 consistent gets

         0 physical reads

         0 redo size

    528561 bytes sent via SQL*Net to client

     23030 bytes received via SQL*Net from client

      2048 SQL*Net roundtrips to/from client

         0 sorts (memory)

          0 sorts (disk)

     30701 rows processed

这里就可以发现,走全表扫描的消耗是要低于走索引的,

即当存在大量重复值的情况下,不会走索引是正确的CBO计算方法。

 

 

 

DUMP 出root的块:

branch: 0x1077233 17265203 (0: nrow: 44,level: 1)

 

 

SQL> selectdbms_utility.data_block_address_file(17265203) fno,dbms_utility.data_block_address_block(17265203)bno from dual;

 

       FNO BNO

———- ———-

        4 487987

SQL> alter system dump datafile 4 block487987;

 

SQL> SELECTd.VALUE

  2|| ‘/’

  3|| LOWER (RTRIM (i.INSTANCE, CHR (0)))

  4|| ‘_ora_’

  5|| p.spid

  6|| ‘.trc’ trace_file_name

  7FROM (SELECT p.spid

  8FROM SYS.v_$mystat m, SYS.v_$session s, SYS.v_$process p

  9WHERE m.statistic# = 1 AND s.SID = m.SID AND p.addr = s.paddr) p,

 10(SELECT t.INSTANCE

 11FROM SYS.v_$thread t, SYS.v_$parameter v

 12WHERE v.NAME = ‘thread’

 13AND (v.VALUE = 0 OR t.thread# = TO_NUMBER (v.VALUE))) i,

 14(SELECT VALUE

 15FROM SYS.v_$parameter

 16WHERE NAME = ‘user_dump_dest’) d ;

 

TRACE_FILE_NAME

——————————————————————————–

/u01/oracle/diag/rdbms/test/test/trace/test_ora_32698.trc

 

Branch blockdump

=================

header address 182926594636=0x2a9746524c

kdxcolev 1

           —索引层级号

KDXCOLEV Flags = – – –

kdxcolok 0

      该索引上是否有DML活动事务

kdxcoopc 0x80: opcode=0: iot flags=— isconverted=Y

 

kdxconco 2

      索引条目中列的数量

kdxcosdc 1

      索引结构发生变化的数量,当你修改某个索引键值时,该值加1

kdxconro 111

     —-当前索引节点中索引条目的数量

kdxcofbo 250=0xfa

      当前索引节点从第几个字节开始记录

kdxcofeo 6561=0x19a1

      当前索引节点可用空间的最尾端在哪个字节

kdxcoavs 6311

             当前索引节点可用空间总量。也就是kdxcofeo – kdxcofbo 的值

kdxbrlmc 17265206=0x1077236

     分支节点的位置

kdxbrsno 102

        最后一个被修改的索引条目号

kdxbrbksz 8056

     用数据块大小,从这里我们可以知道,即便pctfree为0,对于8k数据块,我们也不能完全用完

kdxbr2urrc 0

 

 

row#0[7624] dba: 17265279=0x107727f

col 0; len 3; (3): c2 03 47

col 1; TERM

      其中,col 1表示所链接的分支节点的地址,如果根节点下没有其他的分支节点,则col 1TERMcol 0表示该分支节点所链接的最小键值。注意一点,这里的col 0; len 3; (3):–列的行号,从0开始,紧接着的就是列的长度以及列的值,那么这个值称之为separator key,这个separatorkey 可以区分真实的索引值,所以从这里我们也知道 branch block不会存储完整的索引值,只要能区分就行。也就是说,Oracle Branchblock中只记录索引键值的前缀,而不是所有值,是因为这样可以节约空间,从而能够存储更多的索引条目。同时,我们也能理解了为什么查询使用like ‘%xxx’ 这种方法不会走Btree 索引,因为Branchblock 存储的是前缀。

 

 

row#1[7610] dba: 17265273=0x1077279

col 0; len 2; (2): c2 06

col 1; len 6; (6): 01 07 72 71 01 4e

row#2[7596] dba: 17271438=0x1078a8e

col 0; len 2; (2): c2 06

col 1; len 6; (6): 01 07 8a 86 00 14

row#3[7582] dba: 17271439=0x1078a8f

col 0; len 2; (2): c2 06

col 1; len 6; (6): 01 07 8a 86 01 37

row#4[8047] dba: 17265207=0x1077237

col 0; len 3; (3): c2 06 20

col 1; TERM

row#5[8011] dba: 17265238=0x1077256

col 0; len 2; (2): c2 09

col 1; TERM

row#6[7997] dba: 17265239=0x1077257

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 2c 00 4d

row#7[7983] dba: 17265232=0x1077250

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 2c 01 70

row#8[7969] dba: 17265233=0x1077251

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 2d 00 36

row#9[7955] dba: 17265234=0x1077252

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 2d 01 59

row#10[8033] dba: 17265204=0x1077234

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 2e 01 fe

row#11[8019] dba: 17265205=0x1077235

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 2f 02 01

row#12[7899] dba: 17265250=0x1077262

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 58 00 c7

row#13[7885] dba: 17265251=0x1077263

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 58 01 ea

row#14[7759] dba: 17265257=0x1077269

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 59 00 b0

row#15[7745] dba: 17265258=0x107726a

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 59 01 d3

row#16[7871] dba: 17265252=0x1077264

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 5a 00 b0

row#17[7857] dba: 17265253=0x1077265

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 5a 01 d3

row#18[7843] dba: 17265254=0x1077266

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 5b 00 99

row#19[7829] dba: 17265255=0x1077267

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 5b 01 bc

row#20[7815] dba: 17265249=0x1077261

col 0; len 2; (2): c2 0b

col 1; len 6; (6): 01 07 72 5c 00 82

row#21[7801] dba: 17265262=0x107726e

 

dump下叶子节点:

leaf: 0x1077236 17265206 (-1: nrow: 279rrow: 279)

 

 

SQL> selectdbms_utility.data_block_address_file(17265206)fno,dbms_utility.data_block_address_block(17265206) bno from dual;

 

       FNO BNO

———- ———-

        4 487990

 

SQL> altersystem dump datafile 4 block 487987;

 

System altered.

 

 

 

 

Block headerdump: 0x01077236

 Object id on Block? Y

 seg/obj: 0x24dac csc: 0xbe5.20f8656f itc: 2flg: E typ: 2 – INDEX

    brn: 0 bdba: 0x1077230 ver: 0x01 opc: 0

    inc: 0 exflg: 0

 

 Itl Xid Uba Flag Lck Scn/Fsc

0x01 0x0076.021.00004f42 0x00c07a19.0596.01-BU- 1 fsc 0x0000.20f86570

0x020x0000.000.00000000 0x00000000.0000.00 —- 0 fsc 0x0000.00000000

Leaf block dump

===============

header address 182926594660=0x2a97465264

kdxcolev 0

KDXCOLEV Flags = – – –

kdxcolok 1

kdxcoopc 0x80: opcode=0: iot flags=— isconverted=Y

kdxconco 2

kdxcosdc 2

kdxconro 279

kdxcofbo 594=0x252

kdxcofeo 4516=0x11a4

kdxcoavs 3922

kdxlespl 0

           当前叶子节点被拆分时,未提交的事务数量

kdxlende 0

          被删除的索引条目数量

kdxlenxt 17265279=0x107727f

         当前叶子节点指向的下一个叶子节点的地址

kdxleprv 0=0x0

                  当前叶子节点指向的下一个叶子节点的地址,这里是第一个,所以是0

kdxledsz 0

           被删除的空间

kdxlebksz 8032

row#0[4516] flag: ——, lock: 0, len=12

col 0; len 2; (2): c1 02

col 1; len 6; (6): 01 07 72 2b 00 00

row#1[4528] flag: ——, lock: 0, len=12

col 0; len 2; (2): c1 02

col 1; len 6; (6): 01 07 72 2b 00 0a

row#2[4540] flag: ——, lock: 0, len=12

col 0; len 2; (2): c1 03

col 1; len 6; (6): 01 07 72 2b 00 01

row#3[4552] flag: ——, lock: 0, len=12

col 0; len 2; (2): c1 03

col 1; len 6; (6): 01 07 72 2b 00 0b

 

 

我们再次dump出这个数据块指向的下一个块:

17265279=0x107727f  

leaf: 0x107727f 17265279 (0: nrow: 275rrow: 275)

selectdbms_utility.data_block_address_file(17265279)fno,dbms_utility.data_block_address_block(17265279) bno from dual;

SQL> selectdbms_utility.data_block_address_file(17265279)fno,dbms_utility.data_block_address_block(17265279) bno from dual;

 

       FNO BNO

———- ———-

        4 488063

 

SQL> altersystem dump datafile 4 block 488063;

 

System altered.

 

Block headerdump: 0x0107727f

 Object id on Block? Y

 seg/obj: 0x24dac csc: 0xbe5.20f867f4 itc: 2flg: E typ: 2 – INDEX

    brn: 0 bdba: 0x1077278 ver: 0x01 opc: 0

    inc: 0 exflg: 0

 

 Itl Xid Uba Flag Lck Scn/Fsc

0x01 0x0069.010.0000160c 0x00c010bc.0174.01-BU- 1 fsc 0x0000.20f867f7

0x020x0000.000.00000000 0x00000000.0000.00 —- 0 fsc 0x0000.00000000

Leaf block dump

===============

header address 182926594660=0x2a97465264

kdxcolev 0

KDXCOLEV Flags = – – –

kdxcolok 1

kdxcoopc 0x80: opcode=0: iot flags=— isconverted=Y

kdxconco 2

kdxcosdc 2

kdxconro 275

kdxcofbo 586=0x24a

kdxcofeo 4504=0x1198

kdxcoavs 3918

kdxlespl 0

kdxlende 0

kdxlenxt 17265273=0x1077279

            —-下一个叶子块

kdxleprv 17265206=0x1077236

              —前一个的确是前面dump出的数据块

kdxledsz 0

kdxlebksz 8032

row#0[4504] flag: ——, lock: 0, len=13

col 0; len 3; (3): c2 03 47

col 1; len 6; (6): 01 07 72 2b 01 17

row#1[4517] flag: ——, lock: 0, len=13

col 0; len 3; (3): c2 03 48

col 1; len 6; (6): 01 07 72 2b 01 18

row#2[4530] flag: ——, lock: 0, len=13

col 0; len 3; (3): c2 03 49

col 1; len 6; (6): 01 07 72 2b 01 19

row#3[4543] flag: ——, lock: 0, len=13

col 0; len 3; (3): c2 03 4a

col 1; len 6; (6): 01 07 72 2b 01 1a

row#4[4556] flag: ——, lock: 0, len=13

col 0; len 3; (3): c2 03 4b

col 1; len 6; (6): 01 07 72 2b 01 1b

row#5[4569] flag: ——, lock: 0, len=13

col 0; len 3; (3): c2 03 4c

col 1; len 6; (6): 01 07 72 2b 01 1c

row#6[4582] flag: ——, lock: 0, len=13

col 0; len 3; (3): c2 03 4d

col 1; len 6; (6): 01 07 72 2b 01 1d

row#7[4595] flag: ——, lock: 0, len=13

col 0; len 3; (3): c2 03 4e

 

    转储文件中接下来的部分就是索引条目部分。lock:0 表示ITL中的锁信息 0表示没有被锁len :表示索引值长度flag 表示标记,如删除标记等。col 表示列号,从0开始那么接下来就是索引的键值以及 rowid中后三部分(相对文件号、块号、行号)即:col 0 是键值, col 1 rowid

    也就是说,Leaf节点主要存储了完整的索引键值,以及相关索引键值的部分rowid(这个rowid去掉了data object number部分),同时leaf 节点还存储了2个指针(DBA),他们分别指向上一个leaf节点以及下一个leaf节点.这样叶子节点便是双向链表的结构。我们看到前面对B树索引的体系结构的描述,可以知道其为一个树状的立体结构。

    oracle需要获得一个索引块时,首先从根节点开始,根据所要查找的键值,从而知道其所在的下一层的分支节点,然后访问下一层的分支节点,再次同样根据键值访问再下一层的分支节点,如此这般,最终访问到最底层的叶子节点。可以看出,其获得物理I/O块时,是一个接着一个,按照顺序,串行进行的。在获得最终物理块的过程中,我们不能同时读取多个块,因为我们在没有获得当前块的时候是不知道接下来应该访问哪个块的。因此,在索引上访问数据块时,会对应到db file sequential read等待事件,其根源在于我们是按照顺序从一个索引块跳到另一个索引块,从而找到最终的索引块的。

 

    原文作者:B树
    原文地址: https://blog.csdn.net/bestpaydata/article/details/42876403
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞