Oracle DataBlock是如何存放數據的

問題:
1、Oracle DataBlock是如何存放數據的
2、當發生Update導致記錄變大時,Oracle是如何保證Rowid不變的
3、發生行遷移和行連接的條件是什麼
4、Update後留下的空間是如何被再次利用的

構造測試環境  

create table MILIATEST
(
 ID     NUMBER(
10),
 NAME   VARCHAR2(
2000),
 ADRESS VARCHAR2(
2000)
) tablespace test;


SQL> select b.tablespace_name,b.block_size,b.segment_space_management from dba_tablespaces b where tablespace_name=
'TEST';

TABLESPACE_NAME                BLOCK_SIZE SEGMENT_SPACE_MANAGEMENT
------------------------------ ---------- ------------------------
TEST                          
8192       MANUAL                  手動管理表空間


SQL> select a.pct_free,a.pct_used from all_tables a where a.table_name=
'MILIATEST';

 PCT_FREE   PCT_USED
---------- ----------
       
10         40

SQL> set serverout on;
SQL> exec show_space(
'MILIATEST');

Free Blocks.............................
0
Total Blocks............................
8
Total Bytes.............................
65536
Unused Blocks...........................
7
Unused Bytes............................
57344
Last Used Ext FileId....................
6
Last Used Ext BlockId...................
33
Last Used Block.........................
1


SQL> alter system dump datafile
6 block 33;
System altered 
可以看到MILIATEST段,佔用的8block ,33block存放了段的一些信息

Start dump data blocks tsn:
7 file#: 6 minblk 33 maxblk 33
buffer tsn:
7 rdba: 0x01800021 (6/33)
scn:
0x0000.002169b6 seq: 0x01 flg: 0x04 tail: 0x69b61001
frmt:
0x02 chkval: 0x289a type: 0x10=DATA SEGMENT HEADER - UNLIMITED
Hex dump of block: st=
0, typ_found=1
Dump of memory from
0x090C8400 to 0x090CA400
90C8400 0000A210 01800021002169B6 04010000 [....!....i!.....]
90C8410 0000289A000000000000000000000000 [.(..............]
90C8420 00000000000000010000000700001020 [............ ...]
90C8430 00000000000000000000000701800022 [............"...]
90C8440 00000000 00000000 00000000 00000000 [................]
90C8450 00000000 00000000 00000000 00000001 [................]
90C8460 00000000 0000CF2C 40000000 01800022 [....,......@"...]
90C8470 00000007000000000000000000000000 [................]
90C8480 00000000000000000000000000000000 [................]
        Repeat
250 times
90C9430 00000000000100000001000100000000 [................]
90C9440 00000000000000000000000000000000 [................]
        Repeat
250 times
90CA3F0 00000000000000000000000069B61001 [...............i]
 Extent Control Header
 
-----------------------------------------------------------------
 Extent Header:: spare1:
0      spare2: 0      #extents: 1      #blocks: 7    
                  last map 
0x00000000 #maps: 0      offset: 4128 
    
 Highwater:: 0x01800022 ext#: 0      blk#: 0      ext size: 7    
 #blocks in seg. hdr
's freelists: 0    
 #blocks below: 0    
 mapblk 0x00000000 offset: 0    
                   Unlocked
     Map Header:: next 0x00000000 #extents: 1    obj#: 53036 flag: 0x40000000
 Extent Map
 -----------------------------------------------------------------
   0x01800022 length: 7    
 
 nfl = 1, nfb = 1 typ = 1 nxf = 0 ccnt = 0
 SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000
 rdba: 0x01800021 表示此時的datablock address 0x01800021
 Highwater:: 0x01800022 表示此時的HWM地址爲0x01800022
 
向表裏插入3條數據:
declare
m_name varchar2(
2000):='';
begin
for i in
1..10 loop
m_name:=m_name||
'a';
end loop;
for j in
1..3 loop
insert into MILIATEST(ID,name) values(j,m_name);
commit;
end loop;
end;
 
 
SQL> exec show_space('MILIATEST');
Free Blocks.............................1
Total Blocks............................8
Total Bytes.............................65536
Unused Blocks...........................6
Unused Bytes............................49152
Last Used Ext FileId....................6
Last Used Ext BlockId...................33
Last Used Block.........................2
 
此時段MILIATEST用了2block33放了段head信息,34放數據信息。
SQL> alter system dump datafile 6 block min 33 block max 34;
System altered
 
Start dump data blocks tsn: 7 file#: 6 minblk 33 maxblk 34
buffer tsn: 7 rdba: 0x01800021 (6/33)
scn: 0x0000.00216f8b seq: 0x01 flg: 0x04 tail: 0x6f8b1001
frmt: 0x02 chkval: 0x289a type: 0x10=DATA SEGMENT HEADER - UNLIMITED
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x090C8400 to 0x090CA400
90C8400 0000A210 01800021 00216F8B 04010000 [....!....o!.....]
90C8410 0000289A 00000000 00000000 00000000 [.(..............]
90C8420 00000000 00000001 00000007 00001020 [............ ...]
90C8430 00000000 00000001 00000007 01800023 [............#...]
90C8440 00000000 00000000 00000001 00000001 [................]
90C8450 00000000 00000000 00000000 00000001 [................]
90C8460 00000000 0000CF2C 40000000 01800022 [....,......@"...]
90C8470 00000007 00000000 00000000 00000000 [................]
90C8480 00000000 00000000 00000000 00000000 [................]
        Repeat 250 times
90C9430 00000000 00010000 00010001 00000001 [................]
90C9440 00000000 00000001 01800022 01800022 [........"..."...]
90C9450 00000000 00000000 00000000 00000000 [................]
        Repeat 249 times
90CA3F0 00000000 00000000 00000000 6F8B1001 [...............o]
 Extent Control Header
 -----------------------------------------------------------------
 Extent Header:: spare1: 0      spare2: 0      #extents: 1      #blocks: 7    
                  last map 0x00000000 #maps: 0      offset: 4128 
      Highwater:: 0x01800023 ext#: 0      blk#: 1      ext size: 7  --此時HWM爲:0x01800023
 #blocks in seg. hdr's freelists: 1    
 #blocks below: 1    
 mapblk 0x00000000 offset: 0    
                   Unlocked
     Map Header:: next 0x00000000 #extents: 1    obj#: 53036 flag: 0x40000000
 Extent Map
 -----------------------------------------------------------------
   0x01800022 length: 7    
 
 nfl = 1, nfb = 1 typ = 1 nxf = 0 ccnt = 1
 SEG LST:: flg: USED   lhd: 0x01800022 ltl: 0x01800022
buffer tsn: 7 rdba: 0x01800022 (6/34)
scn: 0x0000.00217094 seq: 0x02 flg: 0x06 tail: 0x70940602
frmt: 0x02 chkval: 0x22ca type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x090C8400 to 0x090CA400
90C8400 0000A206 01800022 00217094 06020000 [...."....p!.....]
90C8410 000022CA 00000001 0000CF2C 00217093 [."......,....p!.]
90C8420 00000000 00030002 00000000 000B0002 [................]
90C8430 00000200 00800345 00190179 00002001 [....E...y.... ..]
90C8440 00217094 002A0003 0000020D 008003DB [.p!...*.........]
90C8450 00260161 00008000 00217045 00030100 [a.&.....Ep!.....]
90C8460 0018FFFF 1F551F6D 00001F55 1F8F0003 [....m.U.U.......]
90C8470 1F6D1F7E 00000000 00000000 00000000 [~.m.............]
90C8480 00000000 00000000 00000000 00000000 [................]
        Repeat 499 times
90CA3C0 00000000 00000000 02012C00 0A04C102 [.........,......]
90CA3D0 61616161 61616161 002C6161 03C10202 [aaaaaaaaaa,.....]
90CA3E0 6161610A 61616161 2C616161 C1020200 [.aaaaaaaaaa,....]
90CA3F0 61610A02 61616161 61616161 70940602 [..aaaaaaaaaa...p]
Block header dump: 0x01800022
 Object id on Block? Y
 seg/obj: 0xcf2c csc: 0x00.217093 itc: 2 flg: O typ: 1 - DATA
     fsl: 0 fnx: 0x0 ver: 0x01
 
 Itl           Xid                  Uba         Flag Lck        Scn/Fsc
0x01   0x0002.00b.00000200 0x00800345.0179.19 --U-    1 fsc 0x0000.00217094
0x02   0x0003.02a.0000020d 0x008003db.0161.26 C---    0 scn 0x0000.00217045
 
data_block_dump,data header at 0x90c845c
===============
tsiz: 0x1fa0   --Total data area size 8kblock: 8192-20(block head)-24(Transaction Header)-24*2(一個事務條)-4(block tail)=8096(0x1fa0)
hsiz: 0x18     --data head size   
pbl: 0x090c845c
bdba: 0x01800022
     76543210
flag=--------
ntab=1                      --表示存放一張表的數據,當存放cluster時,可能出現ntab1
nrow=3                      --表示現在該block 內有三行數據
frre=-1
fsbo=0x18                  --表示可以放數據的空間的起始位置(發現該值和hsiz保持一至)
fseo=0x1f6d                --表示可以存放數據的end位置: 8062
avsp=0x1f55
tosp=0x1f55
0xe:pti[0] nrow=3 offs=0
0x12:pri[0] offs=0x1f8f   --0x1f8f+tl:17=8079+17=8096
0x14:pri[1] offs=0x1f7e  --0x1f7e+t1:17=8062+17=8079
0x16:pri[2] offs=0x1f6d   --0x1f6d+t1:17=8045+17=8062
block_row_dump:
tab 0, row 0, @0x1f8f
tl: 17 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [ 2] c1 02
col 1: [10] 61 61 61 61 61 61 61 61 61 61
tab 0, row 1, @0x1f7e
tl: 17 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [ 2] c1 03
col 1: [10] 61 61 61 61 61 61 61 61 61 61
tab 0, row 2, @0x1f6d
tl: 17 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 04
col 1: [10] 61 61 61 61 61 61 61 61 61 61
end_of_block_dump
End dump data blocks tsn: 7 file#: 6 minblk 33 maxblk 34
 
分析上面的灰色部分,翻譯如下:
 
90CA3C0 00000000 00000000 02012C00 0A04C102 [.........,......]
翻譯:                         002C0102 02C1040A  
          . . . . . . . . . , . . . . . .                    
90CA3D0 61616161 61616161 002C6161 03C10202 [aaaaaaaaaa,.....]
          61616161 61616161 61612C00 0202C103
          a a a a a a a a a a, . . . . .
90CA3E0 6161610A 61616161 2C616161 C1020200 [.aaaaaaaaaa,....]
          0A616161 61616161 6161612C 000202C1
          . a a a a a a a a a a,   . . . .
90CA3F0 61610A02 61616161 61616161 70940602 [..aaaaaaaaaa...p]
          020A6161 61616161 61616161 02069470 –最後四位爲block tail
          . . a a a a a a a a a a   . . . P
0x12:pri[0] offs=0x1f8f 對應得物理地址爲90CA3EB-90CA3FB17個字節
0x14:pri[1] offs=0x1f7e  對應得物理地址爲90CA3DA-90CA3EA17個字節
0x16:pri[2] offs=0x1f6d  對應得物理地址爲90CA3C9-90CA3D917個字節
0,1,2對應rowid的行號,如下:
 
SQL> select a.id,a.name,dbms_rowid.rowid_block_number(rowid) blockid,dbms_rowid.rowid_row_number(rowid) row# from miliatest a;

         ID NAME             BLOCKID       ROW#
----------- --------------- ---------- ----------
         
1 aaaaaaaaaa        34          0
         
2 aaaaaaaaaa        34          1
         
3 aaaaaaaaaa        34          2
 
注:ROWID組成 OOOOOOFFFBBBBBBRRR 其中,O是對象IDF是文件IDB是塊IDR是行ID
   通過分析導出的文件,我們看到rowid裏存放了偏移量數組下標,即所說的行ID,
   而沒有直接在rowid裏存放偏移量,那oracle爲何要如此設計呢,猜想,一個重要原因
   是可以在做更新操作的時候(非分區表),而不需要修改索引(更新列不爲索引列)
在做更新操作的時候,偏移量會改變嗎?
SQL> select rowid
 2 from miliatest a
 3 where id=2;
 
ROWID
------------------
AAAM8sAAGAAAAAiAAB
 
更新第二條記錄:
declare
m_address varchar2(
2000):='';
begin
for i in
1..2000 loop
m_address:=m_address||
'b';
end loop;
update MILIATEST
   set ADRESS=m_address
 where id=
2;
commit;
end;
 
 
SQL> select dbms_rowid.rowid_block_number(rowid) blockid,dbms_rowid.rowid_row_number(rowid) row#
 2 from miliatest a
 3 where id=2;
 
   BLOCKID       ROW#
---------- ----------
34                          1
 
SQL> select rowid
 2 from miliatest a
 3 where id=2;
 
ROWID
------------------
AAAM8sAAGAAAAAiAAB
 
可以看出更新後rowid沒有變化。
alter system dump datafile 6 block 34;
 
Dump of memory from 0x090C8400 to 0x090CA400
90C8400 0000A206 0180002200217CB3 02020000 [...."....|!.....]
90C8410 00000000 00000001 0000CF2C 00217093 [........,....p!.]
90C8420 00000000 00030002 00000000 000B0002 [................]
90C8430 00000200 00800345 00190179 00002001 [....E...y.... ..]
90C8440 00217094 002F000A 000001C5 0080014B [.p!.../.....K...]
90C8450 0016016D 00002001 00217CB3 00030100 [m.... ...|!.....]
90C8460 0018FFFF 17821789 00001782 1F8F0003 [................]
90C8470 1F6D1789 00000000 00000000 00000000 [..m.............]
90C8480 00000000 00000000 00000000 00000000 [................]
        Repeat 373 times
90C9BE0 00000000 03022C00 0A03C102 61616161 [.....,......aaaa]
90C9BF0 61616161 D0FE6161 62626207 62626262 [aaaaaa...bbbbbbb]
90C9C00 62626262 62626262 62626262 62626262 [bbbbbbbbbbbbbbbb]
        Repeat 123 times
90CA3C0 62626262 62626262 02012C62 0A04C102 [bbbbbbbbb,......]-
更新後第1
90CA3D0 61616161 61616161 002C6161 03C10202 [aaaaaaaaaa,.....]-2
90CA3E0 6161610A 61616161 2C616161 C1020200 [.aaaaaaaaaa,....]-更新前第1行(這裏的數據已經無效了,因爲第1行偏移量地址已經改變)
90CA3F0 61610A02 61616161 61616161 7CB30602 [..aaaaaaaaaa...|]
0
Block header dump: 0x01800022
 Object id on Block? Y
 seg/obj: 0xcf2c csc: 0x00.217093 itc: 2 flg: O typ: 1 - DATA
     fsl: 0 fnx: 0x0 ver: 0x01
 
 Itl           Xid                  Uba         Flag Lck        Scn/Fsc
0x01   0x0002.00b.00000200 0x00800345.0179.19 --U-    1 fsc 0x0000.00217094
0x02   0x000a.02f.000001c5 0x0080014b.016d.16 --U-    1 fsc 0x0000.00217cb3
 
data_block_dump,data header at 0x90c845c
===============
tsiz: 0x1fa0
hsiz: 0x18
pbl: 0x090c845c
bdba: 0x01800022
     76543210
flag=--------
ntab=1
nrow=3
frre=-1
fsbo=0x18
fseo=0x1789
avsp=0x1782
tosp=0x1782
0xe:pti[0] nrow=3 offs=0
0x12:pri[0] offs=0x1f8f
0x14:pri[1] offs=0x1789 –更新後第1行偏移量地址改變了,而第0行和第2行沒有影響
-0x1789+ tl: 2020=8062,此時fseo=0x1789
0x16:pri[2] offs=0x1f6d
block_row_dump:
tab 0, row 0, @0x1f8f
tl: 17 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [ 2] c1 02
col 1: [10] 61 61 61 61 61 61 61 61 61 61
tab 0, row 1, @0x1789
tl: 2020 fb: --H-FL-- lb: 0x2 cc: 3
col 0: [ 2] c1 03
col 1: [10] 61 61 61 61 61 61 61 61 61 61
col 2: [2000]
 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62
 62 62 62 62 62 62........................................................
 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62
tab 0, row 2, @0x1f6d
tl: 17 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 04
col 1: [10] 61 61 61 61 61 61 61 61 61 61
end_of_block_dump
 
 
設計修改數據導致產生行遷移:
declare
m_address varchar2(
2000):='';
m_name varchar2(
2000):='';
begin
for i in
1..2000 loop
m_address:=m_address||
'b';
end loop;
for i in
1..1000 loop
m_name:=m_name||
'c';
end loop;
for j in
1..3 loop
update MILIATEST
   set ADRESS=m_address
      ,name=m_name
 where id=j;
commit;
end loop;
end;
 
SQL> exec show_space('MILIATEST');
 
Free Blocks.............................1
Total Blocks............................8
Total Bytes.............................65536
Unused Blocks...........................5
Unused Bytes............................40960
Last Used Ext FileId....................6
Last Used Ext BlockId...................33
Last Used Block.........................3 
 
Start dump data blocks tsn: 7 file#: 6 minblk 34 maxblk 35
buffer tsn:
7 rdba: 0x01800022 (6/34)
scn:
0x0000.0021803d seq: 0x04 flg: 0x02 tail: 0x803d0604
frmt:
0x02 chkval: 0x0000 type: 0x06=trans data
Hex dump of block: st=
0, typ_found=1

tsiz:
0x1fa0
hsiz:
0x18
pbl:
0x090c845c
bdba:
0x01800022
    
76543210
flag=
--------
ntab=
1
nrow=
3
frre=-
1
fsbo=
0x18
fseo=
0x80f
avsp=
0x7f7
tosp=
0x7f7
0xe:pti[0] nrow=3 offs=0
0x12:pri[0] offs=0x13dc =5084+3012byte=8096
0x14:pri[1] offs=0x13d3 =5075 +9byte=5084
0
x16:pri[2] offs=0x80f   +3012byte=5075
block_row_dump:
tab
0, row 0, @0x13dc
tl:
3012 fb: --H-FL-- lb: 0x0 cc: 3
col 
0: [ 2] c1 02
col 
1: [1000]
 
63636363636363636363636363636363636363636363636363
 ..........................................................................
 
63636363636363636363636363636363636363636363636363
col 
2: [2000]
 
63636363636363636363636363636363636363636363636363
 .........................................................................
 
63636363636363636363636363636363636363636363636363
tab 0, row 1, @0x13d3
tl: 9 fb: --H----- lb: 0x0 cc: 0
列的個數爲0,表示沒有存放數據
nrid: 0x01800023.0      
表示遷移的地址爲 rdba0x01800023,行號爲0的地方     
tab 0, row 2, @0x80f

tl:
3012 fb: --H-FL-- lb: 0x2 cc: 3
col 
0: [ 2] c1 04
col 
1: [1000]
 
63636363636363636363636363636363636363636363636363
 .........................................................................
 
63636363636363636363636363636363636363636363636363
col 
2: [2000]
 
62626262626262626262626262626262626262626262626262
 .........................................................................
 
62626262626262626262626262626262626262626262626262
end_of_block_dump
 
我們再看看block35dump文件:
buffer tsn: 7 rdba: 0x01800023 (6/35)
scn:
0x0000.0021803b seq: 0x05 flg: 0x02 tail: 0x803b0605
frmt:
0x02 chkval: 0x0000 type: 0x06=trans data
Hex dump of block: st=
0, typ_found=1
Dump of memory from
0x090C8400 to 0x090CA400

Block header dump
0x01800023
 Object id on Block? Y
 seg/obj:
0xcf2c csc: 0x00.218039 itc: 3 flg: O typ: 1 - DATA
     fsl:
0 fnx: 0x0 ver: 0x01
 
 Itl           Xid                  Uba         Flag Lck        Scn/Fsc
0x01   0x0009.00b.00000216 0x00800058.0198.1c --U-    1 fsc 0x0000.0021803b
0x02   0x0000.000.00000000 0x00000000.0000.00 ----    0 fsc 0x0000.00000000
0x03   0x0000.000.00000000 0x00000000.0000.00 C---    0 scn 0x0000.00000000
 
data_block_dump,data header at
0x90c8474
===============
tsiz:
0x1f88
hsiz:
0x14
pbl:
0x090c8474
bdba:
0x01800023
    
76543210
flag=
--------
ntab=
1
nrow=
1
frre=-
1
fsbo=
0x14
fseo=
0x13be
avsp=
0x13aa
tosp=
0x13aa
0xe:pti[0] nrow=1 offs=0
0x12:pri[0] offs=0x13be
block_row_dump:
tab
0, row 0, @0x13be
tl:
3018 fb: ----FL-- lb: 0x1 cc: 3
hrid: 0x01800022.1 --表示這行是從rdba0x01800022,行號爲1的地方遷移來的
col 
0: [ 2] c1 03
col 
1: [1000]
 
62626262626262626262626262626262626262626262626262
 .........................................................................
 
62626262626262626262626262626262626262626262626262
col 
2: [2000]
 
62626262626262626262626262626262626262626262626262
 .........................................................................
 
62626262626262626262626262626262626262626262626262
end_of_block_dump
 
爲什麼說上面發生的是行遷移而不是行鏈接呢?
要解答這個問題,就要明白行鏈接和行遷移的區別了,發生行遷移後,在dump文件裏該行的cc: 0  列的個數爲0
而發生行鏈接,cc的個數是不爲零的,在原來的地址仍然存放着數據的。
 
從上面地實驗可以看出oracle 是這樣存儲和訪問數據的:
結論:
1、當我們往非分區表裏插入一條數據後:在block內記錄下它的行id(安先後插入順序,從0開始),以及它在block內的偏移量地址(offs=XXXX)
oracle數據是從block底向上存放的,第一次Insert時offs從大到小
2、當我們修改數據時,行id是不變的,也就是它的rowid不變,而只是修改偏移量數組中對應的偏移量
Oracle在通過rowid讀取數據時,先定位block,在通過行id,得到offs,最後得到具體值
當全表掃描時,在同一個block內數據順序是偏移量數組的順序,不是實際存放數據的順序,發生行遷移後遵循block順序
3、行遷移時,它的rowid也是不變的,只是在原來存放數據的地方放一個nrid,指示數據被存放的block地址及行號。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章