Oracle B-Tree Index 原理
一. B-Tree Index 原理
官网说明:
No index structure can satisfy all needs, but the self-balancing B-tree index comes closest to optimizing the performance of searches on large sets of data. Each B-tree node holds multiple keys and pointers. The maximum number of keys in a node supported by a specific B-tree is the order of that tree. Each node has a potential of order+1 pointers to the level below it.
For example, the order=2 B-tree illustrated in Figure 7-1 has tree pointers: to child nodes whose value is less than the first key, to the child nodes whose value is greater than the first key and less than the second key, and to the child nodes whose value is greater than the second key. Thus, the B-tree algorithm minimizes the number of reads and writes necessary to locate a record by passing through fewer nodes than in a binary tree algorithm, which has only one key and at most two children for each decision node. Here we describe the Knuth variation in which the index consists of two parts: a sequence set that provides fast sequential access to the data, and an index set that provides direct access to the sequence set.
Although the nodes of a B-tree generally do not contain the same number of data values, and they usually contain a certain amount of unused space, the B-tree algorithm ensures that the tree remains balanced and that the leaf nodes are at the same level.
Oracle中的Btree Index具有3大结构,root节点,branch节点,leaf节点. Root节点始终紧跟索引段头. 当索引比较小的时候,root节点,branch节点,leaf节点都存储在同一个block中.
Branch节点主要存储了索引的键值,但是这个键值并不是完整的,它只是完整索引值的部分前缀.同时Branch节点还存储了指向leaf节点的指针(DBA),另外有个主意的是branch节点中还有个叫kdxbrlmc的指针.
Oracle rdba和 dba 说明
http://blog.csdn.net/tianlesoftware/archive/2011/06/07/6529346.aspx
Leaf节点主要存储了完整的索引键值,以及相关索引键值的部分rowid(这个rowid去掉了data object number部分),同时leaf 节点还存储了2个指针(DBA),他们分别指向上一个leaf节点以及下一个leaf节点.
Btree Index 是始终平衡的,也就是说 从Root节点到 Leaf 节点的任何一个路径都是等距离的.
Btree Index 默认是按照索引值升序排列的,当然了我们可以在创建/重建的时候设置它降序排列.
Index Scan 的时候,采用的是 sequential read,并且一次只能读一个block(INDEX FAST FULL SCAN 除外).
Btree Index Update的 时候,先做的是 delete,然后进行insert.
Btree Index 不存储 Null值,但是如果组合索引其中一列是非Null的,那么组合索引也会存储Null值.
二. Tree Index 存储原理
2.1 创建测试数据
SYS@anqing2(rac2)> select * from v$version where rownum=1;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Prod
SYS@anqing2(rac2)> create table te as select * from dba_objects;
Table created.
SYS@anqing2(rac2)> select count(*) from te;
COUNT(*)
----------
50258
SYS@anqing2(rac2)> insert into te select * from dba_objects;
50258 rows created.
SYS@anqing2(rac2)> commit;
Commit complete.
SYS@anqing2(rac2)> select count(*) from te;
COUNT(*)
----------
100516
SYS@anqing2(rac2)> create index idx_te_object_name on te(object_name);
Index created.
2.2 查看索引的Blevel, 可以通过DBA_INDEXES.Blevel获得
*-Tree level: depth of the index from its root block to its leaf blocks. A depth of 0 indicates that the root block and leaf block are the same.
--从 root block 到 leaf block的深度. 如果root block 和 leaf block在同一个块中 那么 Blevel=0
SYS@anqing2(rac2)> select index_name,blevel from dba_indexes where index_name='IDX_TE_OBJECT_NAME';
INDEX_NAME BLEVEL
------------------------------ ----------
IDX_TE_OBJECT_NAME 2
2.3 查看索引的height,索引的高度等于Blevel+1,height可以通过INDEX_STATS获得
SYS@anqing2(rac2)> select name,height from index_stats where name='IDX_TE_OBJECT_NAME';
no rows selected
--- index_stats需要 analyze ... validate structure 收集一下,否则无数据
SYS@anqing2(rac2)> analyze index IDX_TE_OBJECT_NAME validate structure;
Index analyzed.
SYS@anqing2(rac2)> select name,height from index_stats where name='IDX_TE_OBJECT_NAME';
NAME HEIGHT
------------------------------ ----------
IDX_TE_OBJECT_NAME 3
2.4 dump index
Oracle 提供了分析 Btree index 结构的命令 treedump,在进行treedump之前需要获得索引的object_id
SYS@anqing2(rac2)> select object_id from dba_objects where object_name='IDX_TE_OBJECT_NAME' and owner='SYS';
OBJECT_ID
----------
SYS@anqing2(rac2)> oradebug setmypid
Statement processed.
SYS@anqing2(rac2)> alter session set events 'immediate trace name treedump level 54769';
Session altered.
SYS@anqing2(rac2)> oradebug tracefile_name
/u01/app/oracle/admin/anqing/udump/anqing2_ora_3865.trc
2.5 查看 treedump trace 文件
[oracle@rac2 ~]$ cat /u01/app/oracle/admin/anqing/udump/anqing2_ora_3865.trc
/u01/app/oracle/admin/anqing/udump/anqing2_ora_3865.trc
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Production
With the Partitioning, Real Application Clusters, OLAP, Data Mining
and Real Application Testing options
ORACLE_HOME = /u01/app/oracle/product/10.2.0/db_1
System name: Linux
Node name: rac2
Release: 2.6.18-194.el5
Version: #1 SMP Tue Mar 16 21:52:43 EDT 2010
Machine: i686
Instance name: anqing2
Redo thread mounted by this instance: 2
Oracle process number: 29
Unix process pid: 3865, image: oracle@rac2 (TNS V1-V3)
*** 2011-06-27 13:15:00.375
*** ACTION NAME:() 2011-06-27 13:15:00.371
*** MODULE NAME:(sqlplus@rac2 (TNS V1-V3)) 2011-06-27 13:15:00.371
*** SERVICE NAME:(SYS$USERS) 2011-06-27 13:15:00.371
*** SESSION ID:(130.55497) 2011-06-27 13:15:00.371
----- begin tree dump
branch: 0x4117c2 4265922 (0: nrow: 2, level: 2)
branch: 0x412086 4268166 (-1: nrow: 250, level: 1)
leaf: 0x4117c3 4265923 (-1: nrow: 182 rrow: 182)
leaf: 0x4117c4 4265924 (0: nrow: 182 rrow: 182)
leaf: 0x4117c5 4265925 (1: nrow: 186 rrow: 186)
leaf: 0x4117c6 4265926 (2: nrow: 189 rrow: 189)
leaf: 0x4117c7 4265927 (3: nrow: 186 rrow: 186)
leaf: 0x4117c8 4265928 (4: nrow: 190 rrow: 190)
leaf: 0x4117c9 4265929 (5: nrow: 186 rrow: 186)
leaf: 0x4117ca 4265930 (6: nrow: 178 rrow: 178)
leaf: 0x4117cb 4265931 (7: nrow: 187 rrow: 187)
leaf: 0x4117cc 4265932 (8: nrow: 182 rrow: 182)
......
leaf: 0x412080 4268160 (244: nrow: 222 rrow: 222)
leaf: 0x412081 4268161 (245: nrow: 201 rrow: 201)
leaf: 0x412082 4268162 (246: nrow: 240 rrow: 240)
leaf: 0x412083 4268163 (247: nrow: 226 rrow: 226)
leaf: 0x412084 4268164 (248: nrow: 211 rrow: 211)
branch: 0x41227b 4268667 (0: nrow: 245, level: 1)
leaf: 0x412085 4268165 (-1: nrow: 229 rrow: 229)
leaf: 0x412087 4268167 (0: nrow: 218 rrow: 218)
leaf: 0x412088 4268168 (1: nrow: 231 rrow: 231)
leaf: 0x412109 4268297 (2: nrow: 249 rrow: 249)
......
leaf: 0x412278 4268664 (241: nrow: 191 rrow: 191)
leaf: 0x412279 4268665 (242: nrow: 180 rrow: 180)
leaf: 0x41227a 4268666 (243: nrow: 56 rrow: 56)
----- end tree dump
2.6 解释 treedump 输出
branch 表示的是 branch block ,它后面跟了一个十六进制表示的DBA(data block address),以及用10进制表示的DBA 。
DBA 之后表示在同一层次的相对位置(root 从0开始,branch 以及leaf从 -1开始)
nrow 表示块中包含了多少条目(包括delete的条目)
rrow 表示块中包含的实际条目(不包括delete的条目)
level 表示从该block到leaf的深度(leaf没有 level)
2.6.1 branch: 0x4117c2 4265922 (0: nrow: 2, level: 2) 说明
这个 branch block 的 level 为2,也就是说 从这个branch block 到 leaf block 的深度为2,根据前面的查询,这个索引的Blevel为2,所以这个branch其实是 root block. 其实根据 nrow:2 也可以看出来它是root block,因为nrow:2 说明它只包含了2个条目,那么这2个条目其实就是dump 文件中的其他2个 branch block 的条目
现在我来验证一下 branch: 0x4117c2 4265922 (0: nrow: 2, level: 2) 是不是 root block , 我查询这个 branch 的 DBA 。
SYS@anqing2(rac2)> select dbms_utility.data_block_address_file('4265922') FILE_ID, dbms_utility.data_block_address_block('4265922') BLOCK_ID from dual;
FILE_ID BLOCK_ID
---------- ----------
1 71618
Btree 索引的 root block总是segment header+1,所以我查询该索引的段头
SYS@anqing2(rac2)> select header_file,header_block from dba_segments where segment_name='IDX_TE_OBJECT_NAME';
HEADER_FILE HEADER_BLOCK
----------- ------------
1 71617
那么现在已经证明了 branch: 0x4117c2 4265922 (0: nrow: 2, level: 2) 是root block, 其实 treedump第一个 branch block 就是 root block。
2.6.2 branch: 0x412086 4268166 (-1: nrow: 250, level: 1) 说明
这个branch 的 DBA为0x412086 (十六进制),4268166 (十进制) ,-1 表示它是与它在同一个深度的 branch block中的第一个 branch block。
nrow: 250 :表示它有247个 leaf block.
level: 1 :表示 这个 branch block 到 leaf block的深度为1
2.6.3 leaf: 0x4117c3 4265923 (-1: nrow: 182 rrow: 182) 说明
leaf 表示它是一个 leaf block 0x4117c3 4265923 分别是这个 leaf block 的 十六进制/十进制的DBA.
-1 表示它是 leaf block 中的第一个 block
nrow: 182 表示它一共有182条记录
rrow: 182 表示它实际有182条记录
2.7 branch block dump
这里选择dump branch: branch: 0x412086 4268166 (-1: nrow: 250, level: 1)
SYS@anqing2(rac2)> select dbms_utility.data_block_address_file('4268166') FILE_ID, dbms_utility.data_block_address_block('4268166') BLOCK_ID from dual;
FILE_ID BLOCK_ID
---------- ----------
1 73862
SYS@anqing2(rac2)> oradebug tracefile_name
/u01/app/oracle/admin/anqing/udump/anqing2_ora_3865.trc
-- 先清空一下
[oracle@rac2 ~]$ cat /dev/null > /u01/app/oracle/admin/anqing/udump/anqing2_ora_3865.trc
SYS@anqing2(rac2)> alter system dump datafile 1 block 73862;
System altered.
2.7.1 部分 DUMP 文件
[oracle@rac2 ~]$ cat /u01/app/oracle/admin/anqing/udump/anqing2_ora_3865.trc
*** 2011-06-27 14:35:54.038
Start dump data blocks tsn: 0 file#: 1 minblk 73862 maxblk 73862
buffer tsn: 0 rdba: 0x00412086 (1/73862)
scn: 0x0000.004e24ec seq: 0x02 flg: 0x04 tail: 0x24ec0602
frmt: 0x02 chkval: 0x3371 type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x0E707400 to 0x0E709400
E707400 0000A206 00412086 004E24EC 04020000 [..... A..$N.....]
......
E7093F0 00000000 00000000 00000000 24EC0602 [...............$]
Block header dump: 0x00412086
Object id on Block? Y
seg/obj: 0xd5f1 csc: 0x00.4e24c9 itc: 1 flg: - typ: 2 - INDEX
fsl: 0 fnx: 0x0 ver: 0x01
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0xffff.000.00000000 0x00000000.0000.00 C--- 0 scn 0x0000.004e24c9
Branch block dump
=================
header address 242250820=0xe707444
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2
kdxcosdc 0
kdxconro 249
kdxcofbo 526=0x20e
kdxcofeo 557=0x22d
kdxcoavs 31
kdxbrlmc 4265923=0x4117c3
kdxbrsno 0
kdxbrbksz 8056
kdxbr2urrc 0
row#0[8023] dba: 4265924=0x4117c4
col 0; len 24; (24):
2f 31 30 64 65 32 32 63 36 5f 43 6c 61 73 73 54 79 70 65 49 6d 70 6c 32
col 1; len 3; (3): 00 41 1b
row#1[7984] dba: 4265925=0x4117c5
col 0; len 30; (30):
2f 31 31 64 35 30 39 31 32 5f 44 61 74 65 46 6f 72 6d 61 74 5a 6f 6e 65 44
61 74 61 5f 7a
col 1; len 3; (3): 00 41 1c
row#2[7973] dba: 4265926=0x4117c6
col 0; len 5; (5): 2f 31 32 61 32
col 1; TERM
row#3[7931] dba: 4265927=0x4117c7
col 0; len 30; (30):
2f 31 33 38 35 32 32 37 66 5f 4d 61 70 52 65 67 69 6f 6e 43 6f 6e 74 61 69
6e 6d 65 6e 74
col 1; len 6; (6): 00 41 18 d5 00 08
......
row#247[571] dba: 4268163=0x412083
col 0; len 6; (6): 41 4c 4c 5f 45 56
col 1; TERM
row#248[557] dba: 4268164=0x412084
col 0; len 8; (8): 41 4c 4c 5f 4d 50 5f 50
col 1; TERM
----- end of branch block dump -----
End dump data blocks tsn: 0 file#: 1 minblk 73862 maxblk 73862
[oracle@rac2 ~]$
2.7.2解释部分dump输出
kdxcolev 1 --该block到leaf block的深度(leaf block 为0).这里branch block 的level 为1 与前面查询相吻合
KDXCOLEV Flags = - - -
kdxcolok 0 --表示是否有事务lock了这个branch block,如果有,有多少事务
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2 --索引值条目. 这里表示有2个条目
kdxcosdc 0 --这个block的结构被更改次数.这里0表示没有更改
kdxconro 249 --索引条目(不包含kdxbrlmc 指针)
kdxcofbo 526=0x20e --空闲空间的起始偏移量
kdxcofeo 557=0x22d --空闲空间的末尾偏移量
kdxcoavs 31 --block中的空闲空间=kdxcofeo-kdxcofbo
kdxbrlmc 4265923=0x4117c3 --如果index value小于row#0,指向该 block 的地址
kdxbrsno 0 --最后被更改的索引条目
kdxbrbksz 8056 --块中的可用空间
kdxbr2urrc 0
row#0[8023] dba: 4265924=0x4117c4 --row# 表示索引条目数,从0开始,紧接着就是十进制和十六进制的DBA,该DBA指向 leaf block
col 0; len 24; (24): --列的行号,从0开始,紧接着的就是列的长度以及列的值,那么这个值称之为separator key,这个separator key 可以区分真实的索引值,所以从这里我们也知道 branch block不会存储完整的索引值,只要能区分就行
2f 31 30 64 65 32 32 63 36 5f 43 6c 61 73 73 54 79 70 65 49 6d 70 6c 32
col 1; len 3; (3): 00 41 1b
2.8 leaf block DUMP
这里选择 row#247[571] dba: 4268163=0x412083, 因为它包含的索引键很少
row#247[571] dba: 4268163=0x412083
col 0; len 6; (6): 41 4c 4c 5f 45 56
col 1; TERM
dump 之前先看一下 row#247[571] 存储的 ' 41 4c 4c 5f 45 56' 是什么索引键. 使用如下代码转换:
SQL> set serveroutput on
/* Formatted on 2011/6/27 16:53:27 (QP5 v5.163.1008.3004) */
DECLARE
n VARCHAR2 (2000);
BEGIN
DBMS_STATS.convert_raw_value ('41', n);
DBMS_OUTPUT.put_line (n);
DBMS_STATS.convert_raw_value ('4c', n);
DBMS_OUTPUT.put_line (n);
DBMS_STATS.convert_raw_value ('4c', n);
DBMS_OUTPUT.put_line (n);
DBMS_STATS.convert_raw_value ('5f', n);
DBMS_OUTPUT.put_line (n);
DBMS_STATS.convert_raw_value ('45', n);
DBMS_OUTPUT.put_line (n);
DBMS_STATS.convert_raw_value ('46', n);
DBMS_OUTPUT.put_line (n);
END;
这个键值代表:
A
L
L
_
E
F
-- 查看file_id 和 block_id
SYS@anqing2(rac2)> select dbms_utility.data_block_address_file('4268163') FILE_ID, dbms_utility.data_block_address_block('4268163') BLOCK_ID from dual;
FILE_ID BLOCK_ID
---------- ----------
1 73859
SYS@anqing2(rac2)> alter system dump datafile 1 block 73859;
System altered.
SYS@anqing2(rac2)> oradebug tracefile_name
/u01/app/oracle/admin/anqing/udump/anqing2_ora_3865.trc
2.8.1 部分DUMP文件
[oracle@rac2 ~]$ cat /u01/app/oracle/admin/anqing/udump/anqing2_ora_3865.trc
*** 2011-06-27 17:00:01.805
Start dump data blocks tsn: 0 file#: 1 minblk 73859 maxblk 73859
buffer tsn: 0 rdba: 0x00412083 (1/73859)
scn: 0x0000.004e24ec seq: 0x02 flg: 0x04 tail: 0x24ec0602
frmt: 0x02 chkval: 0xb42b type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x0E707400 to 0x0E709400
E707400 0000A206 00412083 004E24EC 04020000 [..... A..$N.....]
......
E7093F0 00000000 00000000 00000000 24EC0602 [...............$]
Block header dump: 0x00412083
Object id on Block? Y
seg/obj: 0xd5f1 csc: 0x00.4e24c9 itc: 2 flg: - typ: 2 - INDEX
fsl: 0 fnx: 0x0 ver: 0x01
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
0x02 0xffff.000.00000000 0x00000000.0000.00 C--- 0 scn 0x0000.004e24c9
Leaf block dump
===============
header address 242250844=0xe70745c
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2
kdxcosdc 0
kdxconro 226
kdxcofbo 488=0x1e8
kdxcofeo 1324=0x52c
kdxcoavs 836
kdxlespl 0
kdxlende 0
kdxlenxt 4268164=0x412084
kdxleprv 4268162=0x412082
kdxledsz 0
kdxlebksz 8032
row#0[7999] flag: ------, lock: 0, len=33
col 0; len 23; (23):
41 4c 4c 5f 45 56 41 4c 55 41 54 49 4f 4e 5f 43 4f 4e 54 45 58 54 53
col 1; len 6; (6): 00 41 1a 71 00 2a
row#1[7966] flag: ------, lock: 0, len=33
col 0; len 23; (23):
41 4c 4c 5f 45 56 41 4c 55 41 54 49 4f 4e 5f 43 4f 4e 54 45 58 54 53
col 1; len 6; (6): 00 41 1a 71 00 2b
row#2[7933] flag: ------, lock: 0, len=33
col 0; len 23; (23):
41 4c 4c 5f 45 56 41 4c 55 41 54 49 4f 4e 5f 43 4f 4e 54 45 58 54 53
col 1; len 6; (6): 00 43 eb 77 00 3d
......
row#224[1357] flag: ------, lock: 0, len=33
col 0; len 23; (23):
41 4c 4c 5f 4d 50 5f 47 52 41 50 48 5f 57 4f 52 4b 53 50 41 43 45 53
col 1; len 6; (6): 00 41 1a ad 00 18
row#225[1324] flag: ------, lock: 0, len=33
col 0; len 23; (23):
41 4c 4c 5f 4d 50 5f 47 52 41 50 48 5f 57 4f 52 4b 53 50 41 43 45 53
col 1; len 6; (6): 00 41 1a ad 00 19
----- end of leaf block dump -----
End dump data blocks tsn: 0 file#: 1 minblk 73859 maxblk 73859
[oracle@rac2 ~]$
2.8.2 解释部分dump输出
kdxcolev 0 --该block到leaf block的深度(leaf block 为0).
KDXCOLEV Flags = - - -
kdxcolok 0 --表示是否有事务lock了这个branch block,如果有 有多少事务
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2 --索引值条目. 这里表示有2个条目
kdxcosdc 0 --这个block的结构被更改次数.这里0表示没有更改
kdxconro 226 --索引条目 ,这里有189个索引条目 它等于 row#225-row#0+1
kdxcofbo 488=0x1e8 --空闲空间的起始偏移量
kdxcofeo 1324=0x52c --空闲空间的末尾偏移量
kdxcoavs 836 --block中的空闲空间=kdxcofeo-kdxcofbo
kdxlespl 0 --block split的时候没有commit的记录的大小(byte)
kdxlende 0 --被删除的条目
kdxlenxt 4268164=0x412084 --指向下一个 leaf block的指针(DBA)
kdxleprv 4268162=0x412082 --指向上一个 leaf block的指针(DBA)
kdxledsz 0 --被删除的空间
kdxlebksz 8032 --可用空间
row#0[7999] flag: ------, lock: 0, len=33
col 0; len 23; (23):
41 4c 4c 5f 45 56 41 4c 55 41 54 49 4f 4e 5f 43 4f 4e 54 45 58 54 53
col 1; len 6; (6): 00 41 1a 71 00 2a
row# 表示索引值的条目,从0开始 lock: 0 表示ITL中的锁信息 0表示没有被锁 len=33 表示索引值长度
col 表示列号,从0开始 那么接下来就是索引的键值 以及 rowid中后23位值。
即:col 0 是键值, col 1 是rowid
下面我们来看一下row#0存储的值是什么 ,先看col 0的键值:
SYS@anqing2(rac2)> declare n varchar2(2000);
2 begin
3 dbms_stats.convert_raw_value('414c4c5f4556414c554154494f4e5f434f4e5445585453',n);
4 dbms_output.put_line(n);
5 end;
6 /
ALL_EVALUATION_CONTEXTS
查看col1 rowid 的值:
ROWID一共用18位表示 :
最前6位表示 data object number
之后后3位表示 datafile number
之后后6位表示 datablock number
最后3位表示 row number
有关rowid 更多内容,参考Blog:
Oracle Rowid 介绍
http://blog.csdn.net/tianlesoftware/archive/2009/12/16/5020718.aspx
SYS@anqing2(rac2)> select to_number('00411a71','xxxxxxxxxxxxxxxx') from dual;
TO_NUMBER('00411A71','XXXXXXXXXXXXXXXX')
----------------------------------------
4266609
这里的rowid其实是除去了 data object number的一部分而已。 即col 1中6位中的前4位。
SYS@anqing2(rac2)> select dbms_utility.data_block_address_file('4266609') FILE_ID,dbms_utility.data_block_address_block('4266609') BLOCK_ID from dual;
FILE_ID BLOCK_ID
---------- ----------
1 72305
SYS@anqing2(rac2)> select dbms_rowid.rowid_relative_fno(rowid)file_id, dbms_rowid.rowid_block_number(rowid)block_id,dbms_rowid.rowid_row_number(rowid) row# from te where object_name='ALL_EVALUATION_CONTEXTS';
FILE_ID BLOCK_ID ROW#
---------- ---------- ----------
1 72305 42
1 72305 43
1 256887 61
1 256887 62
根据这个还原的值我来查询一下
SYS@anqing2(rac2)> select owner,object_name,rowid from te where object_name='ALL_EVALUATION_CONTEXTS';
OWNER OBJECT_NAME ROWID
---------- ------------------------- ------------------
SYS ALL_EVALUATION_CONTEXTS AAANXwAABAAARpxAAq
PUBLIC ALL_EVALUATION_CONTEXTS AAANXwAABAAARpxAAr
SYS ALL_EVALUATION_CONTEXTS AAANXwAABAAA+t3AA9
PUBLIC ALL_EVALUATION_CONTEXTS AAANXwAABAAA+t3AA+
SYS@anqing2(rac2)> select owner,object_name,dump(rowid,16) from te where object_name='ALL_EVALUATION_CONTEXTS';
OWNER OBJECT_NAME DUMP(ROWID,16)
---------- ------------------------- -------------------------------------------
SYS ALL_EVALUATION_CONTEXTS Typ=69 Len=10: 0,0,d5,f0,0,41,1a,71,0,2a
PUBLIC ALL_EVALUATION_CONTEXTS Typ=69 Len=10: 0,0,d5,f0,0,41,1a,71,0,2b
SYS ALL_EVALUATION_CONTEXTS Typ=69 Len=10: 0,0,d5,f0,0,43,eb,77,0,3d
PUBLIC ALL_EVALUATION_CONTEXTS Typ=69 Len=10: 0,0,d5,f0,0,43,eb,77,0,3e
在看一下,在2.8节开始的branch block 信息:
row#247[571] dba: 4268163=0x412083
col 0; len 6; (6): 41 4c 4c 5f 45 56
col 1; TERM
其中col 0,我们转换之后是:ALL_EF,由此可见,col 0 是真正的索引键的前缀。
它是每个具体键值的前一部分,即col0 的一部分。 如:
row#0[7999] flag: ------, lock: 0, len=33
col 0; len 23; (23):
41 4c 4c 5f 45 56 41 4c 55 41 54 49 4f 4e 5f 43 4f 4e 54 45 58 54 53
col 1; len 6; (6): 00 41 1a 71 00 2a
Oracle在 Branch block中只记录 索引键值的前缀,而不是所有值,是因为这样可以节约空间,从而能够存储更多的 索引条目。
同时,我们也能理解了为什么 查询使用 like '%xxx' 这种方法不会走Btree 索引,因为Branch block 存储的是前缀.
说明:
根据robinson 的blog,重新做的测试,原文链接如下:
http://blog.csdn.net/robinson1988/archive/2011/01/04/6116276.aspx
-------------------------------------------------------------------------------------------------------
Blog: http://blog.csdn.net/tianlesoftware
Email: dvd.dba@gmail.com
DBA1 群:62697716(满); DBA2 群:62697977(满) DBA3 群:62697850(满)
DBA 超级群:63306533(满); DBA4 群: 83829929 DBA5群: 142216823
DBA6 群:158654907 聊天 群:40132017 聊天2群:69087192
--加群需要在备注说明Oracle表空间和数据文件的关系,否则拒绝申请