oracle的B-tree索引結構分析

lawzjf發表於2006-04-23

軟體版本:XP sp2,Oracle 10.2.0.1

首先建立測試表:

SQL> create table test_idx
2 as
3 select * from all_objects
4 /

表已建立。


SQL> select count(*) from test_idx;

COUNT(*)
--------------
4473

SQL> desc test_idx
名稱 是否為空? 型別
---------------------------------- --------------- --------------
OWNER NOT NULL VARCHAR2(30)
OBJECT_NAME NOT NULL VARCHAR2(30)
SUBOBJECT_NAME VARCHAR2(30)
OBJECT_ID NOT NULL NUMBER
......

我們在整數列object_id上建立索引:

SQL> create index idxx on test_idx(object_id)
2 /

索引已建立。

查詢新建的表和索引所在的表空間(因為自動段管理與手工管理的不同情況下,表空間中的段頭所佔用的block數是不同的,自動管理情況下,段頭佔用3個block,手工管理佔用1個block):

SQL> select tablespace_name,segment_name
2 from user_segments
3 where segment_name in('TEST_IDX','IDXX')
4 /

TABLESPACE_NAME SEGMENT_NAME
------------------------------ ---------------
USERS TEST_IDX
USERS IDXX

查詢users表空間的段空間管理方式:

SQL> conn system/oracle
已連線。
SQL> select tablespace_name,segment_space_management
2 from dba_tablespaces
3 where tablespace_name='USERS'
4 /

TABLESPACE_NAME SEGMEN
------------------------------ -------------
USERS AUTO


查詢新建索引被分配的block情況:

SQL> col segment_name for a10
SQL> select segment_name,file_id,extent_id,block_id
2 from dba_extents
3 where segment_name='IDXX'
4 /

SEGMENT_NA FILE_ID EXTENT_ID BLOCK_ID
------------------- ------------- ---------------- ----------------
IDXX 4 0 225
IDXX 4 1 233

從上面結果可以知道,新建的索引分配到兩個區,
各有8個block。因為索引所在的表空間為自動段管理,
其中的資料物件被分配的前三個block用來儲存物件的
系統資訊,而物件的真正資料從第4個block開始儲存,
所以,idxx的資料228塊開始儲存。
下面,我們匯出從228開始的三個資料塊內容:

SQL> conn system/oracle
已連線。
SQL> alter system dump datafile 4 block min 228 block max 230;

系統已更改。

在udmp目錄下檢視新生成的匯出檔案,並開啟,可以看出
228塊為root節點,而229及230為兩個葉節點。
摘錄其內容如下(內容經過刪減,但未作更改):

228號:

Branch block dump ---表明這是一個分枝節點,其實這是root節點=================
header address 121512524=0x73e224c
kdxcolev 1 ##index level (0 represents leaf blocks)
KDXCOLEV Flags = - - -
kdxcolok 0 ##denotes whether structural block transaction is occurring
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y ##internal operation code
kdxconco 2 ##index column count
kdxcosdc 0 ##count of index structural changes involving block
kdxconro 9 ##number of index entries (does not include kdxbrlmc pointer)
kdxcofbo 46=0x2e ##offset to beginning of free space within block
kdxcofeo 7979=0x1f2b ##offset to the end of free space (ie. first portion of block containing index data)
kdxcoavs 7933 ##available space in block (effectively area between the two fields above)
kdxbrlmc 16777445=0x10000e5 --這是下層節點的第 一個block號碼 229

kdxbrsno 0 ##last index entry to be modified
kdxbrbksz 8060 ##size of usable block space
kdxbr2urrc 0
row#0[8051] dba: 16777446=0x10000e6 --塊號230
col 0; len 3; (3): c2 12 30 --此塊中的最小的key值
col 1; TERM
row#1[8042] dba: 16777447=0x10000e7 --塊號
col 0; len 3; (3): c2 19 60 --此塊中的最小的key值
col 1; TERM
row#2[8033] dba: 16777448=0x10000e8
col 0; len 3; (3): c2 21 5f
col 1; TERM
row#3[8024] dba: 16777449=0x10000e9
col 0; len 3; (3): c2 29 49
col 1; TERM
……

row#7[7988] dba: 16777453=0x10000ed
col 0; len 3; (3): c2 54 21
col 1; TERM
row#8[7979] dba: 16777454=0x10000ee
col 0; len 3; (3): c2 64 61
col 1; TERM
----- end of branch block dump -----

可以看出,root節點下層共有10個block

相關內容的解釋:

kdxcolev: index level (0 represents leaf blocks)
kdxcolok: denotes whether structural block transaction is occurring
kdxcoopc: internal operation code
kdxconco: index column count
kdxcosdc: count of index structural changes involving block
kdxconro: number of index entries (does not include kdxbrlmc pointer)
kdxcofbo: offset to beginning of free space within block
kdxcofeo: offset to the end of free space (ie. first portion of block containing index data)
kdxcoavs: available space in block (effectively area between the two fields above)


229號:

Leaf block dump
===============
header address 121512548=0x73e2264
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2
kdxcosdc 0
kdxconro 479
kdxcofbo 994=0x3e2
kdxcofeo 1813=0x715
kdxcoavs 819
kdxlespl 0
kdxlende 0
kdxlenxt 16777446=0x10000e6 --下一個block號碼
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 8036
row#0[8023] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 03 3b --此塊中的最小key值

col 1; len 6; (6): 01 00 00 a4 00 00 --rowid
row#1[8010] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 03 3c
col 1; len 6; (6): 01 00 00 a4 00 01
row#2[7997] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 04 0c
col 1; len 6; (6): 01 00 00 a4 00 02
……

row#477[1826] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 12 2e
col 1; len 6; (6): 01 00 00 a9 00 4f
row#478[1813] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 12 2f
col 1; len 6; (6): 01 00 00 aa 00 00
----- end of leaf block dump -----

230號:

Leaf block dump
===============
header address 121512548=0x73e2264
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 2
kdxcosdc 0
kdxconro 479
kdxcofbo 994=0x3e2
kdxcofeo 1814=0x716
kdxcoavs 820
kdxlespl 0
kdxlende 0
kdxlenxt 16777447=0x10000e7 --下一個block號碼

kdxleprv 16777445=0x10000e5 --前一個block號碼

kdxledsz 0
kdxlebksz 8036
row#0[8023] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 12 30
col 1; len 6; (6): 01 00 00 aa 00 01
row#1[8010] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 12 31
col 1; len 6; (6): 01 00 00 aa 00 02
row#2[7997] flag: ------, lock: 0, len=13
col 0; len 3; (3): c2 12 33
col 1; len 6; (6): 01 00 00 aa 00 03
……

關於rowid的換算:索引中的rowid由48個bit構成,前10個bit構成檔案號,中間22個bit構成塊號,最後16個bit構成塊中的行號。

關於整數key值的換算:如229塊中的最小key值為c2 03 3b,先去掉c2,因為c2只表示最高位的位置,後面才是真正資料,03轉換為十進位制為3,減去1為2,3b轉換為十進位制為48+11=59,減去1為58,兩個結果合併到一起,為258,這就是七其儲存的真正資料,簡單表示一下:

  1. c2 03 3b -> 03 3b
  2. 03 -> 0*16+3=3->3-1=2
  3. 3b -> 3*16+14=59 -> 59-1=58
  4. 結果合併得到258

關於字串的換算:直接由十六進位制得到各個ascii碼,然後對應到相應字元。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/37724/viewspace-152533/,如需轉載,請註明出處,否則將追究法律責任。

相關文章