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

  • Post author:
  • Post category:其他






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


条,


root





branch


,和


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


)有效的索引条目的数量,因为索引条目如果被删除,不会立即被清除出索引块中。所以


nrow





rrow


的数量就表示已经被删除的索引条目数量

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-1





5-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

5


0-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 1





TERM





col 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


等待事件,其根源在于我们是按照顺序从一个索引块跳到另一个索引块,从而找到最终的索引块的。



版权声明:本文为bestpaydata原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。