【轉載】行遷移和行連結(row chaining or row migration)

renjixinchina發表於2013-05-31
row chain:When a row is too large to fit into any block, row chaining occurs. In this case, the Oracle devide the row into smaller chunks. each chunk is stored in a block along with the necessary poiters to retrive and assemble the entire row.




row migration:when a row is to be updated and it cannot find the necessary free space in its block, the Oracle will move the entire row into a new block and leave a pointer from the orginal block to the new location. This process is called row migration.








行連結(Row chaining) 與行遷移(Row Migration)
當一行的資料過長而不能插入一個單個資料塊中時,可能發生兩種事情:行連結(row chaining)或行遷移(row migration)。


行連結
當第一次插入行時,由於行太長而不能容納在一個資料塊中時,就會發生行連結。在這種情況下,oracle會使用與該塊連結的一塊或多塊資料塊來容納該行的資料。行連線經常在插入比較大的行時才會發生,如包含long, long row, lob等型別的資料。在這些情況下行連結是不可避免的。


行遷移
當修改不是行連結的行時,當修改後的行長度大於修改前的行長度,並且該資料塊中的空閒空間已經比較小而不能完全容納該行的資料時,就會發生行遷移。在這種情況下,Oracle會將整行的資料遷移到一個新的資料塊上,而將該行原先的空間只放一個指標,指向該行的新的位置,並且該行原先空間的剩餘空間不再被資料庫使用,這些剩餘的空間我們將其稱之為空洞,這就是產生表碎片的主要原因,表碎片基本上也是不可避免的,但是我們可以將其降到一個我們可以接受的程度。注意,即使發生了行遷移,發生了行遷移的行的rowid 還是不會變化,這也是行遷移會引起資料庫I/O效能降低的原因。其實行遷移是行連結的一種特殊形式,但是它的起因與行為跟行連結有很大不同,所以一般把它從行連結中獨立出來,單獨進行處理。
行連結和行遷移引起資料庫效能下降的原因:
引起效能下降的原因主要是由於引起多餘的I/O造成的。當透過索引訪問已有行遷移現象的行時,資料庫必須掃描一個以上的資料塊才能檢索到改行的資料。這主要有一下兩種表現形式:
1) row migration 或row chaining 導致 INSERT 或 UPDATE語句的效能比較差,因為它們需要執行額外的處理
2) 利用索引查詢已經連結或遷移的行的select語句效能比較差,因為它們要執行額外的I/O


如何才能檢測到行遷移與行連結:
在表中被遷移或被連結的行可以透過帶list chained rows選項的analyze語句識別出來。這個命令收集每個被遷移或連結的行的資訊,並將這些資訊放到指定的輸出表中。為了建立這個輸出表,執行指令碼UTLCHAIN.SQL。
SQL> ANALYZE TABLE scott.emp LIST CHAINED ROWS;
SQL> SELECT * FROM chained_rows;


當然你也可以透過檢查v$sysstat檢視中的'table fetch continued row'來檢查被遷移或被連結的行。


SQL> SELECT name, value FROM v$sysstat WHERE name = 'table fetch continued row';
NAME VALUE
---------------------------------------------------------------- ---------
table fetch continued row 308
儘管行遷移與行連結是兩個不同的事情,但是在oracle內部,它們被當作一回事。所以當你檢測行遷移與行連結時,你應該仔細的分析當前你正在處理的是行遷移還是行連結。
解決辦法
o 在大多數情況下,行連結是無法克服的,特別是在一個表包含象LONGS, LOBs 等這樣的列時。當在不同的表中有大量的連結行,並且哪些表的行的長度不是很長時,你可以透過用更大的block size重建資料庫的方法來解決它。


例如:當前你的資料庫的資料塊的大小為4K,但是你的行的平均長度為6k,那麼你可以透過用8k大小的資料塊來重建資料庫的辦法解決行連結現象。


o 行遷移主要是由於設定的PCTFREE引數過小,導致沒有給update操作留下足夠的空閒空間引起。為了避免行遷移,所有被修改的表應該設定合適的PCTFREE 值,以便在每個資料塊內為資料修改保留足夠的空間。可以透過增加PCTFREE值的辦法來避免行遷移,但這種解決辦法是以犧牲更多的空間為代價的,這也就是我們通常所說的以空間換效率。 而且透過增加PCTFREE值的辦法只能緩解行遷移現象,而不能完全解決行遷移,所以較好的辦法是在設定了合適的PCTFREE值的後,在發現行遷移現象比較嚴重時,對錶的資料進行重組。下面是對行遷移資料進行重組的步驟(這種方法也被成為CTAS):
-- Get the name of the table with migrated rows:
ACCEPT table_name PROMPT 'Enter the name of the table with migrated rows: '


-- Clean up from last execution
set echo off
DROP TABLE migrated_rows;
DROP TABLE chained_rows;


-- Create the CHAINED_ROWS table
@.../rdbms/admin/utlchain.sql
set echo on
spool fix_mig
-- List the chained and migrated rows
ANALYZE TABLE &table_name LIST CHAINED ROWS;


-- Copy the chained/migrated rows to another table
create table migrated_rows as
SELECT orig.*
FROM &table_name orig, chained_rows cr
WHERE orig.rowid = cr.head_rowid
AND cr.table_name = upper('&table_name');


-- Delete the chained/migrated rows from the original table
DELETE FROM &table_name WHERE rowid IN (SELECT head_rowid FROM chained_rows);


-- Copy the chained/migrated rows back into the original table
INSERT INTO &table_name SELECT * FROM migrated_rows;


spool off


當對一個表進行全表掃描時,我們實際上忽略行遷移中各個指向其它行的指標,因為我們知道,全表掃描會遍歷全表,最終會讀到發生行遷移的行的行資料,在此時才會處理這些行資料。因此,在全表掃描中,行遷移不會引發其它額外的工作。
當透過索引讀一個表的資料時,被遷移的行會引起額外的I/O操作。這是因為從所引中我們會讀到資料行的rowid,它告訴資料庫到指定檔案的指定資料塊的指定slot上可以找到需要的資料,但是因為發生了行遷移,此處只存放一個指向資料的指標,而不是真正的資料,所以資料庫又需要根據該指標(類似rowid)到指定檔案的指定資料塊的指定slot上去找真正的資料,重複上面的過程,知道找到真正的資料。我們可以看出,這會引入額外的I/O操作。


如何或知行遷移(行連結)嚴重的表呢?

DBA_TABLES檢視的CHAINED_CNT列,該列有該表的連結行計數。


CHAIN_CNT* Number of rows in the table that are chained from one data block to another, or which have migrated to a new block, requiring a link to preserve the old ROWID 也就是說這個欄位的值是行遷移和行連結的總數量,至於要知道具體行遷移有多少,行連結又是多少,ANALYZE TABLE這個命令沒辦法得到,只有透過DUMP BLOCK來區分(方法複雜,故沒有去做)



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

相關文章