查看: 9723|回复: 20

oracle数据库特种恢复技术(二)—块内篇

[复制链接]
论坛徽章:
5
2010新春纪念徽章
日期:2010-03-01 11:07:242012新春纪念徽章
日期:2012-01-04 11:54:26铁扇公主
日期:2012-02-21 15:03:13奥运会纪念徽章:皮划艇静水
日期:2012-09-17 16:05:02优秀写手
日期:2013-12-18 09:29:09
跳转到指定楼层
1#
发表于 2011-11-3 10:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 ubotutwin 于 2012-2-1 10:04 编辑

oracle数据库特种恢复技术(二)—块内篇链接:http://www.itpub.net/thread-1507766-1-1.html
oracle数据库特种恢复技术(三)—转换篇链接:http://www.itpub.net/thread-1507774-1-1.html
Oracle数据库特种恢复技术(四)—实验篇链接:http://www.itpub.net/thread-1510202-1-1.html
oracle数据库特种恢复技术(五)--redo篇链接:http://www.itpub.net/thread-1517926-1-1.html
Oracle数据库特种恢复技术(六)—undo篇链接:http://www.itpub.net/thread-1558146-1-1.html
Oracle 数据库特种恢复技术(七)-总结篇链接:http://www.itpub.net/thread-1558154-1-1.html


继续上一次的内容。

明确了大体思路后,需要进入数据文件内部解析出数据行。结合使用bbed、dump、ue进行观察。分析oracle块内物理结构时可采用的方法是:首先在dump文件中找到所关心的变量,然后在dd输出中对照查找该变量的值并记录偏移量,最后在bbed输出中查看该偏移量对应的数据结构进行验证。Oracle数据库中的V$TYPE_SIZE视图记录了块内各个变量及结构体的长度和简单描述,熟悉后可以简单的通过对变量名缩写的估计找到对应的dump文件中的变量。
首先观察数据库1号文件的377数据块,也就是sys.bootstrap$表的segment head block。

Bbed输出:

BBED> setblock 377

        BLOCK#          377

BBED> map
File: /home/oracle/vie.pdf (1)

Block: 377                                  Dba:0x00400179

------------------------------------------------------------
Unlimited Data Segment Header

struct kcbh, 20 bytes                      a0      

struct ktech, 72 bytes                     a20      

struct ktemh, 16 bytes                     a92      

struct ktetb[1], 8 bytes                   a108     

struct ktshc, 8 bytes                      a4148   

struct ktsfs_seg[1], 20 bytes              a4156   

struct ktsfs_txn[16], 320 bytes            a4176   

ub4 tailchk                                a8188   

dump输出:

*** 2011-10-1122:29:03.808

*** SERVICENAME:(SYS$USERS) 2011-10-11 22:29:03.797

*** SESSIONID:(124.22380) 2011-10-11 22:29:03.797

Start dump datablocks tsn: 0 file#: 1 minblk 377 maxblk 377

buffer tsn: 0rdba: 0x00400179 (1/377)

scn:0x0000.0000014a seq: 0x01 flg: 0x04 tail: 0x014a1001

frmt: 0x02chkval: 0xe733 type: 0x10=DATA SEGMENT HEADER - UNLIMITED

Hex dump ofblock: st=0, typ_found=1

Dump of memoryfrom 0x000000000F1DB600 to 0x000000000F1DD600

00F1DB6000000A210 00400179 0000014A 04010000  [....y.a.J......]

…………省略…………..

00F1DD5F000000000 00000000 00000000 014A1001  [....... .....J.]

  Extent Control Header

-----------------------------------------------------------------

  Extent Header:: spare1: 0      spare2: 0      #extents: 1      #blocks: 7     

                  last map  0x00000000 #maps: 0      offset: 4128  

      Highwater::  0x0040017d ext#: 0      blk#: 3      ext size: 7     

  #blocks in seg. hdr's freelists: 1     
  #blocks below: 3     

  mapblk 0x00000000  offset: 0     

                   Unlocked

     Map Header:: next  0x00000000 #extents: 1    obj#: 56     flag: 0x40000000

  Extent Map

-----------------------------------------------------------------

   0x0040017a length: 7     

  
  nfl = 1, nfb = 1 typ = 1 nxf = 0 ccnt = 3
  SEG LST:: flg: USED   lhd: 0x0040017c ltl: 0x0040017c

End dump datablocks tsn: 0 file#: 1 minblk 377 maxblk 377


dd输出:

00000000h: 10A2 00 00 79 01 40 00 4A 01 00 00 00 00 01 04 ; .?.y.a.J.. ....

00000010h: 33E7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; 3?.. ..... ....

00000020h: 0000 00 00 01 00 00 00 07 00 00 00 20 10 00 00 ; .. ..... ... ...

00000030h: 0000 00 00 03 00 00 00 07 00 00 00 7D 01 40 00 ; .. ..... ...}.a.

00000040h: 0000 00 00 00 00 00 00 01 00 00 00 03 00 00 00 ; .. ..... .......

00000050h: 0000 00 00 00 00 00 00 00 00 00 00 01 00 00 00 ; .. ..... .......

00000060h: 0000 00 00 38 00 00 00 00 00 00 40 7A 01 40 00 ; ....8.. ...az.a.

00000070h: 0700 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .. ..... .......

00000080h: 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .. ..... .......

00000090h: 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .. ..... .......

000000a0h: 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .. ..... .......

…………………省略……………………..

377块的block type为0x10,表示该块是Data segment header block (unlimited extents, no freelist groups),就是mssm下的segment header,而assm的segment header的block type为0x24,表示PAGETABLEEXTENT MAP BLOCK(bbed工具目前不支持assm相关的segment header和三级位图块)。

结合观察三种工具的输出。bbed中的“structktetb[1], 8 bytes  a108” 对应的就是oracle dump输出的extent map,该结构体记录了segment中的extent的首地址。这里有一点特别的地方,在进行分析的过程中发现,存放在assm表空间中的segment的header block中的extent map包涵了三级位图的块,就是说assm管理的下的extent map覆盖整个segment占用的块,而存放在mssm表空间中的segment的header block中的extent map,仅包涵segment中存放数据的块,没有包涵段头块本身。由于sys.bootstrap$表处于system表空间中,因此采用的是mssm的管理方式。

Assm与mssm下的extent map格式是相同的,每个extent的信息占用8字节存储,前4字节记录该extent中的第一个块的dba(data block address),后4字节记录该extent包涵的块的个数,使用bbed对其进行观察:

BBED> pktetb

structktetb[0], 8 bytes                    a108     

   ub4 ktetbdba                             a108     0x0040017a

   ub4 ktetbnbk                             a112      0x00000007
与dump文件中的extent map吻合。
在mssm管理下的extent map是在块108偏移量的位置,那么这个位置是否是固定的,我没有找到相关权威资料,因此进行如下分析:首先从不同的库,取不同数据量的表的segment header block,发现偏移量相同,然后用bbed分析ktetb结构体前面的几个结构体变量:
BBED> map /v
File: /home/oracle/vie.pdf (1)

Block: 377                                  Dba:0x00400179

------------------------------------------------------------
Unlimited Data Segment Header

struct kcbh, 20 bytes                      a0      
    ub1 type_kcbh                           a0      
    ub1 frmt_kcbh                           a1      
    ub1 spare1_kcbh                         a2      
    ub1 spare2_kcbh                         a3      
    ub4 rdba_kcbh                           a4      
    ub4 bas_kcbh                            a8      
    ub2 wrp_kcbh                            a12      
    ub1 seq_kcbh                            a14      
    ub1 flg_kcbh                            a15      
    ub2 chkval_kcbh                         a16      
    ub2 spare3_kcbh                         a18      

struct ktech, 72 bytes                     a20      
    ub4 spare1_ktech                        a20      
    word tsn_ktech                          a24      
    ub4 lastmap_ktech                       a28      
    ub4 mapcount_ktech                      a32      
    ub4 extents_ktech                       a36      
    ub4 blocks_ktech                        a40      
    ub2 mapend_ktech                        a44      
    struct hwmark_ktech, 32 bytes           a48      
    struct locker_ktech, 8 bytes            a80      
    ub4 flag_ktech                          a88      

struct ktemh, 16 bytes                     a92      

    ub4 count_ktemh                         a92     

    ub4 next_ktemh                          a96      
    ub4 obj_ktemh                           a100     
    ub4 flag_ktemh                          a104   
可见前三个结构体都不是数组类型,所以目前判断ktetb的偏移量应该是在数据库版本一定的情况下是固定的存放在块头偏移108的位置。
继续进行观察。将extent map中的dba“0x0040017a”进行转换,其指向1号文件的378号数据块。按377块extent map中所记录,sys.bootstrap$表存储于1号文件378号数据块开始的连续7个数据块中,且ub4 next_ktemh a96的值为0x00000000,因此所有数据都存储在这7个数据块中。

继续深入观察378号数据块就能得到sys.bootstrap$表的真实数据:
bbed输出:

BBED> setblock 378

        BLOCK#          378

BBED> map
File: /home/oracle/vie.pdf (1)

Block: 378                                  Dba:0x0040017a

------------------------------------------------------------
KTB Data Block (Table/Cluster)

struct kcbh, 20 bytes                      a0      

struct ktbbh, 48 bytes                     a20      

struct kdbh, 14 bytes                      a68      

struct kdbt[1], 4 bytes                    a82      

sb2 kdbr[24]                               a86      

ub1 freespace[1158]                        a134     

ub1 rowdata[6896]                          a1292   

ub4 tailchk                                a8188   

oracledump输出:
Start dump data blocks tsn: 0 file#: 1minblk 378 maxblk 378
buffer tsn: 0 rdba: 0x0040017a (1/378)
scn: 0x0000.0000015d seq: 0x01 flg:0x06 tail: 0x015d0601
frmt: 0x02 chkval: 0x13d5 type:0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x000000001E849600to 0x000000001E84B600
01E849600 0000A206 0040017A 0000015D06010000  [....z.a.].. ....]
01E849610 000013D5 00000001 00000038000000C7  [.. .....8.. ....]
01E849620 00000000 00020001 0000000000220000  [.. ..... ,...".],
01E849630 00000002 00400182 000C000200002018  [.. ...a.. ... ..]

……………………………省略部分内容………………………

Block header dump:  0x0040017a
Object id on Block? Y
seg/obj: 0x38 csc: 0x00.c7  itc: 1  flg: - typ: 1 - DATA
    fsl: 0  fnx: 0x0 ver: 0x01

Itl          Xid                  Uba         Flag Lck        Scn/Fsc
0x01  0x0000.022.00000002 0x00400182.0002.0c  --U-   24 fsc 0x0000.0000015d

data_block_dump,data header at0x1e849644
===============
tsiz: 0x1fb8
hsiz: 0x42
pbl: 0x1e849644
bdba: 0x0040017a
    76543210
flag=--------
ntab=1
nrow=24
frre=-1
fsbo=0x42
fseo=0x4c8
avsp=0x486
tosp=0x486
0xe:pti[0]       nrow=24 offs=0
0x12:pri[0]     offs=0x1fa3
0x14:pri[1]     offs=0x1f1a
0x16:pri[2]     offs=0x1d95
0x18:pri[3]     offs=0x1ccd
0x1a:pri[4]     offs=0x1b4e
0x1c:pri[5]     offs=0x1a7a
0x1e:pri[6]     offs=0x19ad
0x20:pri[7]     offs=0x1749
0x22:pri[8]     offs=0x167b
0x24:pri[9]     offs=0x15b3
0x26:pri[10]   offs=0x14d6
0x28:pri[11]   offs=0x140a
0x2a:pri[12]   offs=0x12ef
0x2c:pri[13]   offs=0x1205
0x2e:pri[14]   offs=0x110e
0x30:pri[15]   offs=0xf38
0x32:pri[16]   offs=0xe68
0x34:pri[17]   offs=0xd91
0x36:pri[18]   offs=0xc79
0x38:pri[19]   offs=0x969
0x3a:pri[20]   offs=0x89c
0x3c:pri[21]   offs=0x65e
0x3e:pri[22]   offs=0x58e
0x40:pri[23]   offs=0x4c8
block_row_dump:
tab 0, row 0, a0x1fa3
tl: 21 fb: --H-FL-- lb: 0x1  cc: 3
col 0: [ 3]  3e 64 66
col 1: [ 3]  3e 64 66
col 2: [ 9]  38 2e 30 2e 30 2e 30 2e30
tab 0, row 1, a0x1f1a
tl: 137 fb: --H-FL-- lb: 0x1  cc: 3
col 0: [ 1]  80
col 1: [ 1]  80
col 2: [129]
43 52 45 41 54 45 20 52 4f 4c 4c 42 41 43 4b20 53 45 47 4d 45 4e 54 20 53
59 53 54 45 4d 20 53 54 4f 52 41 47 45 20 2820 20 49 4e 49 54 49 41 4c 20
31 31 32 4b 20 4e 45 58 54 20 31 30 32 34 4b20 4d 49 4e 45 58 54 45 4e 54
53 20 31 20 4d 41 58 45 58 54 45 4e 54 53 2033 32 37 36 35 20 4f 42 4a 4e
4f 20 30 20 45 58 54 45 4e 54 53 20 28 46 494c 45 20 31 20 42 4c 4f 43 4b
20 39 29 29
……………………………..省略………………………

dd输出:
00000000h: 06 A2 00 00 7A 01 40 00 5D 01 00 00 00 00 01 06 ; .?.z.a.]......
00000010h: D5 13 00 00 01 00 00 00 38 00 00 00 C7 00 00 00 ; ?.. ...8...?..
00000020h: 00 00 00 00 01 00 02 00 00 00 00 00 00 00 22 00 ; ....... .....".
00000030h: 02 00 00 00 82 01 40 00 02 00 0C 00 18 20 00 00 ; ....?a..... ..
00000050h: 86 04 00 00 18 00 A3 1F 1A 1F 95 1D CD 1C 4E 1B ;?....?..??N.
00000060h: 7A 1A AD 19 49 17 7B 16 B3 15 D6 14 0A 14 EF 12 ;z.?I.{.??..?
00000070h: 05 12 0E 11 38 0F 68 0E 91 0D 79 0C 69 09 9C 08 ;....8.h.?y.i.?
00000080h: 5E 06 8E 05 C8 04 00 00 00 00 00 00 00 00 00 00 ; ^.??.........
00000090h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ....... .......
000000a0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ....... .......
00000500h: 00 00 00 00 00 00 00 00 00 00 00 00 2C 01 03 02 ; ....... ...,...

…………………………..省略部分内容………………………….

00000510h: C1 08 02 C1 08 BC 43 52 45 41 54 45 20 49 4E 44 ; ?.?糃REATE IND
00000520h: 45 58 20 49 5F 54 53 23 20 4F 4E 20 43 4C 55 53 ; EXI_TS# ON CLUS
00000530h: 54 45 52 20 43 5F 54 53 23 20 50 43 54 46 52 45 ; TERC_TS# PCTFRE
00000540h: 45 20 31 30 20 49 4E 49 54 52 41 4E 53 20 32 20 ; E 10INITRANS 2
00000550h: 4D 41 58 54 52 41 4E 53 20 32 35 35 20 53 54 4F ;MAXTRANS 255 STO
00000560h: 52 41 47 45 20 28 20 20 49 4E 49 54 49 41 4C 20 ; RAGE(  INITIAL
00000570h: 36 34 4B 20 4E 45 58 54 20 31 30 32 34 4B 20 4D ; 64KNEXT 1024K M
00000580h: 49 4E 45 58 54 45 4E 54 53 20 31 20 4D 41 58 45 ;INEXTENTS 1 MAXE
00000590h: 58 54 45 4E 54 53 20 32 31 34 37 34 38 33 36 34 ; XTENTS214748364
000005a0h: 35 20 50 43 54 49 4E 43 52 45 41 53 45 20 30 20 ; 5PCTINCREASE 0
000005b0h: 4F 42 4A 4E 4F 20 37 20 45 58 54 45 4E 54 53 20 ; OBJNO 7EXTENTS
……………………………省略……………………………………
到这里就是非常熟悉的数据块的内容了。观察dd输出可见,由于系统字典全部为ascii码字符,所以已经可以看到表中内容的明文了。

在378号块中,从structkdbh, 14 bytes  a68开始记录的就是块内数据行的相关字典信息,kdbh数据结构的偏移量为:20+24+ ktbbh. Ktbbhict*24。具体含义为kcbh结构体20字节+ktbbh结构体中的固定长度部分24字节+ktbbh中ktbbhitl数组长度(每个itl槽占24字节,itl槽个数记录在ktbbhict变量中)。注:这个偏移量公式只适用于mssm表空间,assm稍有区别,后详述。

继续观察kdbh结构体:
BBED> p kdbh

struct kdbh, 14bytes                       a68      

   ub1 kdbhflag                             a68       0x00 (NONE)
   b1 kdbhntab                              a69       1
   b2 kdbhnrow                              a70       24
   sb2 kdbhfrre                             a72      -1
   sb2 kdbhfsbo                             a74       66
   sb2 kdbhfseo                             a76       1224
   b2 kdbhavsp                              a78       1158
   b2 kdbhtosp                              a80       1158
这里有两个和本文有关的变量;1、kdbhntab­­,块里存放数据属于几个表,普通表这里是1,超过1是簇表。2、Kdbhnrow,块里存放的数据行数。
接下来是struct kdbt[1], 4 bytes   a130数组,该数组的偏移量为kdbh的偏移量+14(kdbh结构体的长度)。该块中存放的数据所属的每个表都要在kdbt数组里占用4字节(一个数组元素)存储相关信息,对于普通表来说,数据块内存储的数据都属于同一个表,因此这个数组的长度肯定为1。
从sb2 kdbr[24]  a86开始记录的就是块内存放的数据行的行偏移量表,每个数据行在行偏移量表里占2字节。该数组本身的物理偏移量为:kdbh的偏移量+14(kdbh结构体的长度)+kdbh结构体中kdbhntab变量的值*4(每个表占4字节)。具体到378数据块就是68+14+1*4=86。在dd输出中找到offset 86的位置:

00000000h: 06 A200 00 7A 01 40 00 5D 01 00 00 00 00 01 06 ; .?.z.a.].. ....

00000010h: D5 1300 00 01 00 00 00 38 00 00 00 C7 00 00 00 ; ?.. ...8...?..

00000020h: 00 0000 00 01 00 02 00 00 00 00 00 00 00 22 00 ; .. ..... .....".

00000030h: 02 0000 00 82 01 40 00 02 00 0C 00 18 20 00 00 ; ....?a.. ... ..

00000040h: 5D 0100 00 00 01 18 00 FF FF 42 00 C8 04 86 04 ; ].. ....B.??

00000050h: 86 0400 00 18 00 A3 1F 1A1F 95 1D CD 1C 4E 1B ; ?....?..??N.

00000060h: 7A 1AAD 19 49 17 7B 16 B3 15 D6 14 0A 14 EF 12 ; z.?I.{.??..?

00000070h: 05 120E 11 38 0F 68 0E 91 0D 79 0C 69 09 9C 08 ; ....8.h.?y.i.?

00000080h: 5E 068E 05 C8 04 00 00 00 00 00 00 00 00 00 00 ; ^.??.. .......

00000090h: 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .. ..... .......

000000a0h: 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 ; .. ..... .......

上面红色白底标注的就是378块offset 86位置。我进行分析所用数据库安装在linux操作系统上,linux操作系统采用Little Endian存储模式,因此一个变量中的各个字节之间的顺序和正常阅读顺序是颠倒的,因此该位置的值是1F A3,与dump文件中行列表中的第一行相吻合。
0x1FA3转换为10进制为8099,前面提到,该偏移量是在kdbh开始计算,因此要加上68,899+68=8167,观察dd输出中8167位置:
……………………………省略前面部分…………………………….

00001f90h: 49 4E49 54 49 41 4C 20 31 31 32 4B 20 4E 45 58 ; INITIAL 112K NEX

00001fa0h: 54 2031 30 32 34 4B 20 4D 49 4E 45 58 54 45 4E ; T 1024K MINEXTEN

00001fb0h: 54 5320 31 20 4D 41 58 45 58 54 45 4E 54 53 20 ; TS 1 MAXEXTENTS

00001fc0h: 33 3237 36 35 20 4F 42 4A 4E 4F 20 30 20 45 58 ; 32765 OBJNO 0 EX

00001fd0h: 54 454E 54 53 20 28 46 49 4C 45 20 31 20 42 4C ; TENTS (FILE 1 BL

00001fe0h: 4F 434B 20 39 29 29 2C 01 03 03 3E 64 66 03 3E ; OCK9)),...>df.>

00001ff0h: 6466 09 38 2E 30 2E 30 2E 30 2E 30 01 06 5D 01 ; df.8.0.0.0.0..].


以上红色白底部分就是8167偏移量位置对应的数据,块最后4个字节“01 06 5D 01”是块的校验信息,不属于数据行内容。从这里可以看出,oracle在将数据写入数据块时是从下往上进行写入的,这是在编程中经常用到的一种数据存储设计方式,在一个固定大小的存储空间中存储不同的数据结构,那么就采用一种数据从上向下增长,另一种数据从下向上增长,这样可以最大限度的利用存储空间。
进一步观察这段数据:

2C01 03 03 3E 64 66 03 3E 64 66 09 38 2E 30 2E 30 2E 30 2E 30

这一行字符,就是该表第一行的全部数据。第一个字节的2C表示该行的row flag,采用的是符号位的存储方式,即该字节的8个比特位分别代表块的一种属性,该比特位为1表示该属性对于该块成立。2C对应为00101100与dump文件中该行的flag相吻合:
tab 0, row 1, a0x1f1a
tl: 137 fb: --H-FL-- lb:0x1  cc: 3
col 0: [ 1]  80
col 1: [ 1]  80
col 2: [129]
4352 45 41 54 45 20 52 4f 4c 4c 42 41 43 4b 20 53 45 47 4d 45 4e 54 20 53
……………………………省略………………………………..
2C即--H-FL--中的H、F、L分别表示head data piece、first data piece、last data piece,这里表示该行数据的以上三个piece全部存储在当前的这个位置,没有行链接现象。如果有行链接,则数据行的三个piece会分别存储到不同的块内。Flag的其他位以后做详细分析。

2C 0103 03 3E 64 66 03 3E 64 66 09 38 2E 30 2E 30 2E 30 2E 30

       第二个字节的01表示行上的锁的状态。

2C 01 0303 3E 64 66 03 3E 64 66 09 38 2E 30 2E 30 2E 30 2E 30

       第三个字节的03表示行内字段的数量,这里要注意的是flag、lock信息、column count三中信息不一定固定为三个字节,在簇表等其他情况下,可能是3字节或者9字节或者19字节等等不同长度,需要针对segment类型分别分析。

2C 01 03 033E 64 66 03 3E 64 66 09 38 2E 30 2E 30 2E 30 2E 30

       第四个字节的03表示之后这个字段(行内存储的第一个字段)占用3个字节存储。提取后面三个字节的内容“3E 64 66”,与sys.bootstrap$表中第一行的第一个字段的值“-1”吻合:
SQL> select dump(-1,16) from dual;
DUMP(-1,16)
---------------------
Typ=2 Len=3: 3e,64,66

2C 01 03 03 3E 64 66 03 3E 64 66 09 38 2E 30 2E30 2E 30 2E 30
第八个字段的03表示第二个字段占用三个字节。

2C 01 03 03 3E 64 66 03 3E 64 66 09 38 2E 30 2E 30 2E30 2E 30
第十二个字节的09表示第三个字段占用9个字节。

这里所举例的bootstrap$表的所有字段都是非空的,如果一行中非末尾字段为空,oracle加入一个值为0xff的字节,如果行最后一个字段为空,那么该字段不记录,就是说如果一行的最后一个字节为空,那么行头记录的字段个数会比结尾字段不为空的行少。
如果一个字段的长度大于256字节,oracle将占用三个字节来记录该字段长度,且这三个字节的第一个字节为“0xfe”。
从这里也可以看出,oracle在一行数据中的各个字段是按照队列的方式存放的,且队列的各个元素不固定长度,所以,当oracle需要读取某行数据的某个字段的值时,需要遍历该字段前的所有字段。因此,在oracle表的设计阶段,根据业务,将使用频繁的列尽量放在表的前面,可以减小数据库内存操作的压力,提升sql执行速度。

再分析索引簇的存储方式。以SYS.SEG$表为例,sys.bootstrap$中该表的定义为:

CREATE TABLE SEG$("FILE#" NUMBER NOTNULL,"BLOCK#" NUMBER NOT NULL,"TYPE#" NUMBER NOTNULL,"TS#" NUMBER NOT NULL,"BLOCKS" NUMBER NOTNULL,"EXTENTS" NUMBER NOT NULL,"INIEXTS" NUMBER NOTNULL,"MINEXTS" NUMBER NOT NULL,"MAXEXTS" NUMBER NOTNULL,"EXTSIZE" NUMBER NOT NULL,"EXTPCT" NUMBER NOTNULL,"USER#" NUMBER NOT NULL,"LISTS"NUMBER,"GROUPS" NUMBER,"BITMAPRANGES" NUMBER NOTNULL,"CACHEHINT" NUMBER NOT NULL,"SCANHINT" NUMBER NOTNULL,"HWMINCR" NUMBER NOT NULL,"SPARE1"NUMBER,"SPARE2" NUMBER) STORAGE ( OBJNO 14 TABNO 2) CLUSTER C_FILE#_BLOCK#(TS#,FILE#,BLOCK#)

通过红色字体白底部分,可见该表属于C_FILE#_BLOCK#簇,而C_FILE#_BLOCK#簇在sys.bootstrap$中的定义为:

CREATE CLUSTERC_FILE#_BLOCK#("TS#" NUMBER,"SEGFILE#"NUMBER,"SEGBLOCK#" NUMBER) PCTFREE 10 PCTUSED 40 INITRANS 2 MAXTRANS255 STORAGE (  INITIAL 24K NEXT 1024KMINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 8 EXTENTS (FILE 1 BLOCK73)) SIZE 225

可见,该簇的segment header block存放在file 1的73号block中。其中extent map的第一行指向file 1的74号block。对该block进行观察:
Bbed输出:

BBED> setblock 74

        BLOCK#          74

BBED> map
File: /home/oracle/vie.pdf (1)

Block: 74                                   Dba:0x0040004a

------------------------------------------------------------
KTB Data Block (Table/Cluster)
struct kcbh, 20 bytes                      a0      
struct ktbbh, 72 bytes                     a20      
struct kdbh, 14 bytes                      a92      
struct kdbt[3], 12 bytes                   a106     
sb2 kdbr[70]                               a118     
ub1 freespace[5084]                        a258     
ub1 rowdata[2846]                          a5342   
ub4 tailchk                                a8188   
oracle dump输出:
       …………………………..省略………………….
Block header dump:  0x0040004a
Object id on Block? Y
seg/obj: 0x8  csc: 0x00.dc780c  itc: 2 flg: -  typ: 1 - DATA
     fsl: 0  fnx: 0x0 ver: 0x01

Itl           Xid                  Uba         Flag Lck        Scn/Fsc
0x01  0x0000.047.00000002 0x0040000e.0000.01  C---    0 scn 0x0000.000000f1
0x02  0x0007.024.000018d8 0x0080190f.0c3c.05  --U-    1 fsc 0x0000.00dc780e

data_block_dump,data header at 0x1cf7365c
===============
tsiz: 0x1fa0
hsiz: 0xa6
pbl: 0x1cf7365c
bdba: 0x0040004a
     76543210
flag=--------
ntab=3
nrow=70
frre=-1
fsbo=0xa6
fseo=0x1482
avsp=0x1410
tosp=0x1410
0xe:pti[0]       nrow=35 offs=0
0x12:pti[1]     nrow=0   offs=35
0x16:pti[2]     nrow=35 offs=35
0x1a:pri[0]     offs=0x1f84
0x1c:pri[1]     offs=0x1f68
0x1e:pri[2]     offs=0x1f4c
0x20:pri[3]     offs=0x1f31
0x22:pri[4]     offs=0x1f15
…………………….省略……………………….
dd输出:
00000000h: 06 A2 00 00 4A 00 40 00 FE 98 ED 00 00 00 01 04 ; .?.J.a.?....
00000010h: 6C D7 00 00 01 00 00 00 08 00 00 00 0C 78 DC 00 ; l?.........x?
00000020h: 00 00 00 00 02 00 02 00 00 00 00 00 00 00 47 00 ; ....... .....G.
00000050h: 3C 0C 05 00 01 20 00 00 0E 78 DC 00 00 03 46 00 ;<.... ...x?..F.
00000060h: FF FF A6 00 82 14 10 14 10 14 00 00 23 00 23 00 ; ??.....#.#.
00000070h: 00 00 23 00 23 00 84 1F 68 1F 4C 1F 31 1F 15 1F ;..#.#.?h.L.1...
00000080h: F9 1E DD 1E C1 1E A5 1E 89 1E 6D 1E 52 1E 36 1E ;?????m.R.6.
00000090h: 1A 1E FE 1D E3 1D C7 1D AB 1D 8F 1D 73 1D 57 1D ; ..?????s.W.
000000a0h: 3C 1D 21 1D 05 1D E9 1C CD 1C B1 1C 96 1C 7A 1C ;<.!...????z.
000000b0h: 5E 1C 42 1C 26 1C 0B 1C EF 1B D3 1B 9F 1B 6B 1B ;^.B.&...???k.
000000c0h: 37 1B 03 1B CE 1A 9A 1A 66 1A 32 1A FE 19 CA 19 ;7...??f.2.??
000000d0h: 96 19 62 19 2E 19 FA 18 C6 18 91 18 5D 18 29 18 ;?b...???].).
000000e0h: F4 17 C0 17 82 14 58 17 24 17 F0 16 BC 16 87 16 ;???X.$.???
000000f0h: 53 16 24 16 F0 15 BB 15 87 15 53 15 1F 15 EB 14 ;S.$.???S...?
通过以下查询,确定C_FILE#_BLOCK#中存放着三个segment的数据,分别是
SYS.UET$、SYS.SEG$和C_FILE#_BLOCK#本身。
SQL> select * from sys.bootstrap$ a where a.sql_text like'%C_FILE#_BLOCK#%';

     LINE#       OBJ# SQL_TEXT
---------- ------------------------------------------------------------------------------------------
        13        13 CREATE TABLE UET$("SEGFILE#" NUMBER NOTNULL,"SEGBLOCK#" NUMBER NOT NULL,"EXT#"
        14         14 CREATE TABLE SEG$("FILE#"NUMBER NOT NULL,"BLOCK#" NUMBER NOT NULL,"TYPE#" NUMBE
         8          8 CREATE CLUSTERC_FILE#_BLOCK#("TS#" NUMBER,"SEGFILE#"NUMBER,"SEGBLOCK#" NUMBER)
         9          9 CREATE INDEX I_FILE#_BLOCK# ONCLUSTER C_FILE#_BLOCK# PCTFREE 10 INITRANS 2 MAXT
在bbed中观察kdbh结构体:
BBED> p kdbh
struct kdbh, 14 bytes                       a92      
   ub1 kdbhflag                             a92      0x00 (NONE)
   b1 kdbhntab                              a93       3
   b2 kdbhnrow                              a94       70
   sb2 kdbhfrre                             a96      -1
   sb2 kdbhfsbo                             a98       166
   sb2 kdbhfseo                             a100      5250
   b2 kdbhavsp                              a102      5136
   b2 kdbhtosp                              a104      5136
kdbh结构体中的kdbhntab变量为3,与分析相符。
按前面分析,kdbt数组的长度是该块内存储的数据所属的对象的个数,每个对象占用4字节存储,该数组内存储的,实际上是每个不同对象在行偏移量列表里所对应的行的范围:
BBED> p kdbt
struct kdbt[0], 4 bytes                     a106     
   b2 kdbtoffs                              a106      0
   b2 kdbtnrow                              a108      35
struct kdbt[1], 4 bytes                     a110     
   b2 kdbtoffs                              a110      35
   b2 kdbtnrow                              a112      0
struct kdbt[2], 4 bytes                     a114     
   b2 kdbtoffs                              a114      35
   b2 kdbtnrow                              a116      35
这里可以看到74号块内存总共放了70行数据,红色部分表示数组的第一个元素,表示第一个对象从第0行开始,共占用35行。
数组的第二个元素表示第二个对象从第35行开始,共占用了0行(其实就是SYS.UET$表,该表内没有数据)。
数组元素的第三个元素表示第三个对象从第35行开始,共占用了35行。
从sb2 kdbr[70]       a118开始,存放着块内数据行的具体偏移量列表,按照上面的分析,计算kdbr结构体的偏移量为:20+24+2*24(该块内有两个itl槽)+14+3*4(该块内有来自三个对象的数据)=118,与bbed中的输出相符:
BBED> map

File: /home/oracle/vie.pdf(1)

Block: 74                                   Dba:0x0040004a

------------------------------------------------------------

KTB Data Block(Table/Cluster)

struct kcbh, 20 bytes                      a0      
struct ktbbh, 72 bytes                     a20      
struct kdbh, 14 bytes                      a92      
struct kdbt[3], 12 bytes                   a106     
sb2 kdbr[70]                               a118     
ub1 freespace[5084]                        a258     
ub1 rowdata[2846]                          a5342   
ub4 tailchk                                a8188
进一步观察数据行内部结构。第一行偏移量为0x1f84换算为十进制为8068,如先前分析,还要加上kdbh的偏移量92,8068+92=8160。bbed中8160位置的数据如下:

00001fe0h: AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00; ?.. ...a.J...a.

00001ff0h: 4A 00 00 01 80 02 C1 02 03 C2 04 26 0106 FE 98 ;

块最后4个字节是校验信息,红色部分就是第一行数据,逐个字节对其进行分析:
AC 00 03 0100 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 01 80 02 C1 02 03 C2 04 26
第一个字节AC转换为2进制10101100,与dump中相符:
tab 0, row 0, a0x1f84
tl: 28 fb: K-H-FL-- lb: 0x0  cc: 3
curc: 1 comc: 1 pk: 0x0040004a.0 nk: 0x0040004a.0
col  0: [ 1]  80
col  1: [ 2]  c1 02
col  2: [ 3]  c2 04 26
这里的flag字节,比之前单个表的flag多了一位“K”,表示本行数据存放的是cluster的key。
AC 00 03 01 00 01 00 00 40 004A 00 00 00 40 00 4A 00 00 01 80 02 C1 02 03 C2 04 26

第二个字节表示该行的锁信息。
AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 01 8002 C1 02 03 C2 04 26

第三个字节表示该行内共存放着3个字段。
AC 00 03 01 00 01 00 00 40 00 4A 0000 00 40 00 4A 00 00 01 80 02 C1 02 03 C2 04 26
从第四个字节开始的总共16个字节,记录了簇的相关信息,具体为
AC 00 03 01 00 01 00 00 40 004A 00 00 00 40 00 4A 00 00 01 80 02 C1 02 03 C2 04 26
第四、五两个字节对应dump文件中的curc的值:

tl: 28 fb: K-H-FL-- lb: 0x0 cc: 3

curc: 1 comc: 1 pk:0x0040004a.0 nk: 0x0040004a.0

col  0: [ 1]  80
col  1: [ 2]  c1 02
col  2: [ 3]  c2 04 26
tab 0, row 1, a0x1f68

AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 0000 01 80 02 C1 02 03 C2 04 26

第六、七两个字节对应dump文件中的comc的值:

tl: 28 fb: K-H-FL-- lb: 0x0 cc: 3

curc: 1 comc: 1 pk: 0x0040004a.0 nk: 0x0040004a.0
col  0: [ 1]  80
col  1: [ 2]  c1 02
col  2: [ 3]  c2 04 26
tab 0, row 1, a0x1f68

AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 004A 00 00 01 80 02 C1 02 03 C2 04 26

八到十三字节记录了簇中具有该key值的前一行的存储位置,对应dump文件中的pk的值,其存储格式为,data block address.row index,表示具有这个key的值的上一行数据的存储位置,这里看到这个值是指向该行自身的,说明本行数据是簇中该key对应的第一行数据:
       tl:28 fb: K-H-FL-- lb: 0x0  cc: 3

curc: 1 comc: 1 pk:0x0040004a.0 nk: 0x0040004a.0

col  0: [ 1] 80

col  1: [ 2]  c1 02
col  2: [ 3]  c2 04 26
tab 0, row 1, a0x1f68

AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 0000 01 80 02 C1 02 03 C2 04 26

十四到十九字节记录了簇中具有该key值的后一行的存储位置,对应dump文件中的nk的值,其存储格式为,data block address.row index,表示具有这个key的值的下一行数据的存储位置,这里看到这个值是指向该行自身的,说明本行数据是簇中该key对应的最后一行数据:

       tl: 28 fb: K-H-FL-- lb:0x0  cc: 3

curc: 1 comc: 1pk: 0x0040004a.0 nk: 0x0040004a.0

col  0: [ 1] 80

col  1: [ 2]  c1 02
col  2: [ 3]  c2 04 26
tab 0, row 1, a0x1f68
既是第一行又是最后一行表示这个键值对应的只有这一行数据。

AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 0180 02 C1 02 03 C2 04 26

下一个字节01表示第一个字段占一个字节存储。

AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 01 8002 C1 02 03 C2 04 26

80是第一个字段的值0的oracle内部表示方法。

AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 01 80 02C1 02 03 C2 04 26

下一个字节02表示第二个字段占两个字节存储。

AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 01 80 02 C102 03 C2 04 26

下两个字节C1 02是数字1的oracle内部表示方法。

AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 01 80 02 C102 03 C2 04 26

下一个字节的03表示第三个字段占三个字节存储。

AC 00 03 01 00 01 00 00 40 00 4A 00 00 00 40 00 4A 00 00 01 80 02 C102 03 C2 04 26

最后三个字节C2 04 26是数字337的oracle内部表示方法。

至此,单表及簇表通过segment header块定为数据行的大体流程已经清晰,总结如下。
对于单表:
1、            在segment header block偏移量96的位置找到ktemh结构体的next_ktemh变量,该变量指向segment的下一个extent map。如果该变量的值为0x00000000,表示该segment的所有数据都存储在一个segment中。
2、             在segment header block偏移量108的位置找到ktetb数组,该数组中每个节点占8字节,前4字节为extent首地址,后4字节为extent内块的个数。
3、             通过extent map找到具体存储数据的块。
4、             在数据块内找到kdbh数据结构,其偏移量为:20+24+ktbbh. Ktbbhict(块内偏移量36位置,长度两字节)*24。
5、             找到kdbr数组,其偏移量为:kdbh的偏移量+14(kdbh结构体的长度)+kdbh结构体中kdbhntab变量的值*4(每个表占4字节)。
6、             取出kdbr中行的偏移量,将该值加上kdbh的偏移量值,得到行物理偏移量。
7、             根据行物理偏移量,找到行数据起始位置,并取出其首字节flag。
根据块的flag判断行头的不同长度。如,普通无行链接数据行,flag为2C对应为二进制00101100 --H-FL—则行内数据位于行头偏移3字节的位置。簇且无行链接数据行,flag为AC对应二进制10101100 K-H-FL—则行内数据位于行头偏移19字节的位置。
8、             在行头第三个字段,取出行内字段个数。
9、             在行头后找到首个字段的长度,并按该长度取出其后的字段值。
10、          按步骤9递归取出行内全部字段的值。

下一步就是要将取出的二进制数据转换为明文。
论坛徽章:
5
ITPUB十周年纪念徽章
日期:2011-11-01 16:20:282012新春纪念徽章
日期:2012-01-04 11:50:442013年新春福章
日期:2013-02-25 14:51:242014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11
2#
发表于 2011-11-3 11:13 | 只看该作者
支持一下。。。。好文

使用道具 举报

回复
论坛徽章:
0
3#
发表于 2011-11-4 15:34 | 只看该作者
好文,绝对要支持

使用道具 举报

回复
论坛徽章:
3
技术图书徽章
日期:2014-06-20 16:30:312015年新春福章
日期:2015-03-04 14:53:162015年新春福章
日期:2015-03-06 11:58:39
4#
发表于 2011-11-7 11:17 | 只看该作者
继续学习中!写的不错!
看样子也该去研究研究了~~

使用道具 举报

回复
论坛徽章:
1
2010新春纪念徽章
日期:2010-03-01 11:20:04
5#
发表于 2011-11-7 14:40 | 只看该作者
加油啊,兄弟!

使用道具 举报

回复
6#
发表于 2011-11-7 14:44 | 只看该作者
ding

使用道具 举报

回复
论坛徽章:
162
红宝石
日期:2012-03-07 17:12:34红宝石
日期:2013-10-25 11:29:16红宝石
日期:2013-10-25 11:29:16红宝石
日期:2013-10-25 11:29:16红宝石
日期:2013-10-25 14:16:34红宝石
日期:2013-10-31 09:12:40紫水晶
日期:2016-05-09 16:06:22海蓝宝石
日期:2012-03-16 10:31:49祖母绿
日期:2013-12-23 21:10:45萤石
日期:2016-05-09 16:06:22
7#
发表于 2011-11-7 16:28 | 只看该作者
很有用,收藏了。

使用道具 举报

回复
论坛徽章:
1
2010新春纪念徽章
日期:2010-03-01 11:20:04
8#
发表于 2011-11-7 16:31 | 只看该作者

使用道具 举报

回复
论坛徽章:
4
2010新春纪念徽章
日期:2010-01-04 08:33:082010新春纪念徽章
日期:2010-03-01 11:20:07ITPUB十周年纪念徽章
日期:2011-11-01 16:24:042012新春纪念徽章
日期:2012-01-04 11:54:26
9#
发表于 2011-11-9 19:27 | 只看该作者
好文章,学习了

使用道具 举报

回复
论坛徽章:
5
2010新春纪念徽章
日期:2010-03-01 11:07:242012新春纪念徽章
日期:2012-01-04 11:54:26铁扇公主
日期:2012-02-21 15:03:13奥运会纪念徽章:皮划艇静水
日期:2012-09-17 16:05:02优秀写手
日期:2013-12-18 09:29:09
10#
 楼主| 发表于 2011-11-10 13:19 | 只看该作者
感谢支持,望多提宝贵意见,谢谢

ps:这万恶的特殊字符啊,整整搞了两天才明白“00000040h: F1 00 00 00 07 00 24 00 D8 18 00 00 0F 19 80 00 ;?....$.?....”文中有类似这样的行,结果造成后面的内容全部被截掉了,看来是和某些网络协议或者论坛代码的关键字冲突了。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表