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+1height可以通过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

----------

     54769   

 

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 表示从该blockleaf的深度(leaf没有 level) 

 

2.6.1  branch: 0x4117c2 4265922 (0: nrow: 2, level: 2) 说明

       这个 branch block level 2,也就是说 从这个branch block leaf block 的深度为2,根据前面的查询,这个索引的Blevel2,所以这个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 DBA0x412086 (十六进制)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 1

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  --blockleaf 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  --blockleaf 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 16位中的前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表空间和数据文件的关系,否则拒绝申请

 

posted @ 2011-06-27 19:50  hibernate我最强  阅读(329)  评论(0编辑  收藏  举报