关于Oracle数据库中行迁移/行链接的问题(一)
在實際的工作中我們經常會碰到一些Oracle數據庫性能較低的問題,當然,引起Oracle數據庫性能較低的原因是多方面的,我們能夠通過一些正確的設計和診斷來盡量的避免一些Oracle數據庫性能不好,Row Migration (行遷移) & Row Chaining (行鏈接)就是其中我們可以盡量避免的引起Oracle數據庫性能低下的潛在問題。通過合理的診斷行遷移/行鏈接,我們可以較大幅度上提高Oracle數據庫的性能。
那究竟什么是行遷移/行鏈接呢,先讓我們從Oracle的block開始談起。
操作系統的最小讀寫操作單元是操作系統的block,所以當創建一個Oracle數據庫的時候我們應該講數據庫的block size設置成為操作系統的block size的整數倍,Oracle block是Oracle數據庫中讀寫操作的最小單元,Oracle9i之前的Oracle數據庫版本中Oracle block一旦在創建數據庫的時候被設定后就沒法再更改。為了在創建數據庫之前確定一個合理的Oracle block的大小,我們需要考慮一些因素,例如數據庫本身的大小以及并發事務的數量等。使用一個合適的Oracle block大小對于數據庫的調優是非常重要的。Oracle block的結構如下圖所示:
? ? ? ? ? ? ? ? ? 圖一:Oracle Block結構圖
由上圖我們可以看出,一個Oracle block由三個部分組成,分別是數據塊頭、自由空間、實際數據三部份組成。
數據塊頭:主要包含有數據塊地址的一些基本信息和段的類型,以及表和包含有數據的實際行的地址。
自由空間:是指可以為以后的更新和插入操作分配的空間,大小由PCTFREE和PCTUSED兩個參數影響。
實際數據:是指在行內存儲的實際數據。
?當創建或者更改任何表和索引的時候,Oracle在空間控制方面使用兩個存儲參數:
?PCTFREE:為將來更新已經存在的數據預留空間的百分比。
?PCTUSED:用于為插入一新行數據的最小空間的百分比。這個值決定了塊的可用狀態??捎玫膲K時可以執行插入的塊,不可用狀態的塊只能執行刪除和修改,可用狀態的塊被放在freelist中。
?當表中一行的數據不能在一個數據block中放入的時候,這個時候就會發生兩種情況,一種是行鏈接,另外一種就是行遷移了。
?行鏈接產生在第一次插入數據的時候如果一個block不能存放一行記錄的情況下。這種情況下,Oracle將使用鏈接一個或者多個在這個段中保留的block存儲這一行記錄,行鏈接比較容易發生在比較大的行上,例如行上有LONG、LONG RAW、LOB等數據類型的字段,這種時候行鏈接是不可避免的會產生的。
?當一行記錄初始插入的時候事可以存儲在一個block中的,由于更新操作導致行長增加了,而block的自由空間已經完全滿了,這個時候就產生了行遷移。在這種情況下,Oracle將會遷移整行數據到一個新的block中(假設一個block中可以存儲下整行數據),Oracle會保留被遷移行的原始指針指向新的存放行數據的block,這就意味著被遷移行的ROW ID是不會改變的。
?當發生了行遷移或者行鏈接,對這行數據操作的性能就會降低,因為Oracle必須要掃描更多的block來獲得這行的信息。
?下面舉例來具體說明行遷移/行鏈接的產生過程。
?先創建一個pctfree為20和pctused為50的測試表:
?create table test(
?col1 char(20),
?col2 number)
?storage (
?pctfree 20
?pctused 50);
?當插入一條記錄的時候,Oracle會在free list中先去尋找一個自由的塊,并且將數據插入到這個自由塊中。而在free list中存在的自由的塊是由pctfree值決定的。初始的空塊都是在free list中的,直到塊中的自由空間達到pctfree的值,此塊就會從free list中移走,而當此塊中的使用空間低于pctused的時候,此塊又被重新放到free list中。
?Oracle使用free list機制可以大大的提高性能,對于每次的插入操作,Oracle只需要查找free list就可以了,而不是去查找所有的block來尋找自由空間。
?假設第一次插入數據使用的一個空的block,如下圖所示:
圖二:Oracle空的block結構圖
假設插入第一條記錄的時候占用一個block的10%的空間(除去block頭占去的大小),剩余的自由空間90%大于pctfree20%,因此這個block還將繼續為下次的插入操作提供空間。
再連續插入七條記錄,使block的剩余自由空間剩下20%,此時,這個block將要從free list中移走,如果再插入記錄,Oracle將再free list中尋找下一個空余的block去存放后來插入的數據。
圖四:插入80%后的Oracle block結構圖
?此時如果去更新第一條插入的記錄,使其行長增加15%,Oracle將會使用這個block中剩余的20%的自由空間來存放此行數據,如果再更新第二條記錄,同樣的使其行長增加15%,而此block中只剩下5%的自由空間,不夠存放更新的第二條記錄,于是Oracle會在free list中尋找一個有自由空間(10%+15%)的block來存放這行記錄的block去存儲,在原來的block中保存了指向新的block的指針,原來這行記錄的ROW ID保持不變,這個時候就產生了行遷移。
?而當我們插入一條新紀錄的時候,如果一個blcok不足以存放下這條記錄,Oracle就會尋找一定數量的block一起來容納這條新的記錄,這個時候就產生了行鏈接,行鏈接主要產生在LOB、CLOB、BLOB和大的VA行鏈接HAR2數據類型上。
?具體我們通過下面的一個試驗來查看行鏈接和行遷移是如何產生并在數據文件中體現出來的。
先查看ALLAN這個表空間的數據文件號,為了便于測試,我只建立了一個數據文件。
SQL> select file_id from dba_data_files where tablespace_name='ALLAN';
? FILE_ID
----------
? ? ? ?23
創建一個測試表test:
SQL> create table test ( x int primary key, a char(2000), b char(2000), c char(2000), d char(2000), e char(2000) ) tablespace allan;
Table created.
因為我的數據庫的db_block_size是8K,所以我創建的表有五個字段,每個占2000個字節,這樣一行記錄大約10K,就能超過一個block的大小了。
然后插入一行記錄,只有一個字段的:
SQL> insert into test(x) values (1);
1 row created.
SQL> commit;
Commit complete.
查找這行記錄所在的block,并dump出來:
SQL> select dbms_rowid.rowid_block_number(rowid) from test;
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
------------------------------------
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?34
SQL> alter system dump datafile 23 block 34;
System altered.
在udump目錄下查看trace文件的內容如下:
Start dump data blocks tsn: 34 file#: 23 minblk 34 maxblk 34
buffer tsn: 34 rdba: 0x05c00022 (23/34)
scn: 0x0000.013943f3 seq: 0x01 flg: 0x02 tail: 0x43f30601
frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
Block header dump: ?0x05c00022
Object id on Block? Y
seg/obj: 0x3ccd ?csc: 0x00.13943ef ?itc: 2 ?flg: O ?typ: 1 - DATA
? ? fsl: 0 ?fnx: 0x0 ver: 0x01
Itl ? ? ? ? ? Xid ? ? ? ? ? ? ? ? ?Uba ? ? ? ? Flag ?Lck ? ? ? ?Scn/Fsc
0x01 ? 0x000a.02e.00000ad7 ?0x00800036.03de.18 ?--U- ? ?1 ?fsc 0x0000.013943f3
0x02 ? 0x0000.000.00000000 ?0x00000000.0000.00 ?---- ? ?0 ?fsc 0x0000.00000000
data_block_dump,data header at 0xadb505c
===============
tsiz: 0x1fa0
hsiz: 0x14
pbl: 0x0adb505c
bdba: 0x05c00022
? ? 76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x1f9a
avsp=0x1f83
tosp=0x1f83
0xe:pti[0] ? ? ?nrow=1 ?offs=0
0x12:pri[0] ? ? offs=0x1f9a
block_row_dump:
tab 0, row 0, @0x1f9a
tl: 6 fb: --H-FL-- lb: 0x1 ?cc: 1
col ?0: [ 2] ?c1 02
end_of_block_dump
End dump data blocks tsn: 34 file#: 23 minblk 34 maxblk 34
對其中的一些信息做一些解釋:
Fb:H是指行記錄的頭,L是指行記錄的最后一列,F是指行記錄的第一列。
Cc:列的數量
Nrid:對于行鏈接或者行遷移來說的下一個row id的值
由上面的dump信息我們可以看出來當前表test是沒有行鏈接或者行遷移的。
然后更新test表,并重新dump出來:
SQL> update test set a='test',b='test',c='test',d='test',e='test' where x=1;
1 row updated.
SQL> commit;
Commit complete.
此時應該有行遷移/行鏈接產生了。
SQL> alter system dump datafile 23 block 34;
System altered.
在udump目錄下查看trace文件的內容如下:
Start dump data blocks tsn: 34 file#: 23 minblk 34 maxblk 34
buffer tsn: 34 rdba: 0x05c00022 (23/34)
scn: 0x0000.0139442b seq: 0x01 flg: 0x02 tail: 0x442b0601
frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
Block header dump: ?0x05c00022
Object id on Block? Y
seg/obj: 0x3ccd ?csc: 0x00.1394429 ?itc: 2 ?flg: - ?typ: 1 - DATA
? ? fsl: 0 ?fnx: 0x0 ver: 0x01
Itl ? ? ? ? ? Xid ? ? ? ? ? ? ? ? ?Uba ? ? ? ? Flag ?Lck ? ? ? ?Scn/Fsc
0x01 ? 0x000a.02e.00000ad7 ?0x00800036.03de.18 ?C--- ? ?0 ?scn 0x0000.013943f3
0x02 ? 0x0004.002.00000ae0 ?0x0080003b.0441.11 ?--U- ? ?1 ?fsc 0x0000.0139442b
data_block_dump,data header at 0xadb505c
===============
tsiz: 0x1fa0
hsiz: 0x14
pbl: 0x0adb505c
bdba: 0x05c00022
? ? 76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x178a
avsp=0x177c
tosp=0x177c
0xe:pti[0] ? ? ?nrow=1 ?offs=0
0x12:pri[0] ? ? offs=0x178a
block_row_dump:
tab 0, row 0, @0x178a
tl: 2064 fb: --H-F--N lb: 0x2 ?cc: 3
nrid: ?0x05c00023.0
col ?0: [ 2] ?c1 02
col ?1: [2000]
74 65 73 74 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
............
col ?2: [48]
74 65 73 74 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
end_of_block_dump
End dump data blocks tsn: 34 file#: 23 minblk 34 maxblk 34
我們不難看出,nrid出現了值,指向了下一個row id,證明剛剛的update操作使這行記錄產生了行鏈接或者行遷移了。
oracle視頻教程請關注:http://u.youku.com/user_video/id_UMzAzMjkxMjE2.html
轉載于:https://blog.51cto.com/19880614/1198895
總結
以上是生活随笔為你收集整理的关于Oracle数据库中行迁移/行链接的问题(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 字节对齐《c和指针》笔记--包含位域结构
- 下一篇: 销售管理软件