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