Oracle資料表預設值列新增與行遷移(Row Migration)
在筆者之前的文章中,已經探討過給一個資料表新增有預設值列是一項非常“危險”的事情,特別是在線上生產環境下。給一張大資料表新增有預設值列,最直接的有下面幾個嚴重危害:
ü 系統高負荷執行,消耗大量資源。新增列操作是一次性的DDL操作,生成大量的Redo Log記錄;
ü 長期資料表鎖定,阻礙生產系統作業。新增資料列期間,對資料表新增獨佔鎖,此時阻礙其他DML操作;
ü 破壞原有儲存結構,造成大量的行遷移(Row Migration)資料。在每個資料行嘗試新增進預設值,進行膨脹的同時,由於rowid的特性,會引起嚴重的行連結情況,損害原有資料表儲存結構;
本文主要想聊聊由於預設值新增帶來的行連結(Row Migration)現象。
1、從Row Migration現象談起
Row Migration本質上是一種由於Oracle儲存特性和資料行定位特性而發生的一種現象。在Oracle中,所有的資料行都是保留在資料塊單元上的。一個資料塊可以容納若干條資料(通常條件下)。一些資料列,如varchar2型別,大部分情況下都是根據輸入資料的長度進行空間分配。
那麼,如果資料行列填入了更大的資料,也就是空間發生了擴充。資料塊儲存上就會發生何種變化呢?每個資料塊都會預留一部分的空閒空間,作為資料行變化預留位置。如果長度繼續擴充,那麼會發生什麼呢?
Oracle會嘗試將這個資料行複製出,找個新的資料塊進行儲存。這樣,就可以放下資料塊。那麼,一個新的問題出現了,就是Rowid問題。
在Oracle中,Rowid是定位一條記錄的實體地址。Rowid包括資料檔案相對編號、物件號、資料塊號和Slot行號。Rowid普遍作為資料行的標記,儲存在相關的索引葉子節點上。但是,當一個資料行被轉移儲存到另一個資料塊,本質上物理儲存位置已經發生變化。索引等物件中包括的Rowid面臨著失效的問題。
Oracle解決這個問題是透過“虛擬門牌”的方法。這個資料行位置雖然已經到另外的地方,但是對應的Rowid並沒有發生變化。當我們檢索資料,Server Process定位到原來的位置時,它會找到一個轉換跳轉地址,那裡面記錄著真正的Rowid地址。這個就是發生了Row Migration。
Row Migration給系統效能帶來了很多潛在的問題。比如,一行資料原來只需要尋找一個資料塊記錄,現在就需要尋找多個資料塊才可以。這樣就是帶來的效能問題。
我們在進行預設值資料行新增的時候,就會帶來Row Migration的爆發。
2、Row Migration與預設值列新增
下面我們透過實驗,來證明Row Migration的出現。我們選擇11gR2環境進行實驗。
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
SQL> create table t as select object_id from dba_objects where 1=0;
Table created
--新增若干條記錄;
SQL> insert into t select object_id from dba_objects where rownum<100;
99 rows inserted
SQL> commit;
Commit complete
資料表T,在儲存結構和空間分配上情況如下:
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);
PL/SQL procedure successfully completed
SQL> select bytes, blocks,extents from user_segments where segment_name='T';
BYTES BLOCKS EXTENTS
---------- ---------- ----------
65536 8 1
SQL> select blocks from user_tables where table_name='T';
BLOCKS
----------
1
User_segment中記錄著給資料段分配的總空間,但這並不代表全部的HWM位置。User_tables中的blocks,才代表HWM下資料塊的個數。從上面的結果看,HWM下一共只有一個資料塊。從rowid分析看,實際也的確如此。
SQL> select dbms_rowid.rowid_block_number(rowid) blockno, count(*) from t group by dbms_rowid.rowid_block_number(rowid);
BLOCKNO COUNT(*)
---------- ----------
85857 99
下面我們進行資料列新增。
SQL> alter table t add vc varchar2(1000) default lpad('T',500,'T');
Table altered
Executed in 0.078 seconds
對應的空間使用情況如下:
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);
PL/SQL procedure successfully completed
Executed in 0.141 seconds
SQL> select blocks from user_tables where table_name='T';
BLOCKS
----------
12
Executed in 0.016 seconds
SQL> select bytes, blocks,extents from user_segments where segment_name='T';
BYTES BLOCKS EXTENTS
---------- ---------- ----------
131072 16 2
SQL> select dbms_rowid.rowid_block_number(rowid) blockno, count(*) from t group by dbms_rowid.rowid_block_number(rowid);
BLOCKNO COUNT(*)
---------- ----------
85857 99
Executed in 0.016 seconds
上面的情況可以看出,Oracle的資料表T已經推高了水位線HWM到12個塊,從空間分配也分配了新的extent使用。
但是,所有資料行rowid沒有變化。所有資料行的“門牌號”都沒有變化,但是儲存呢?很詭異的增加了。正常容量下,資料塊情況應該是如下:
SQL> create table t_bak as select * from t;
Table created
SQL> exec dbms_stats.gather_table_stats(user,'T_BAK',cascade => true);
PL/SQL procedure successfully completed
SQL> select bytes, blocks,extents from user_segments where segment_name='T_BAK';
BYTES BLOCKS EXTENTS
---------- ---------- ----------
131072 16 2
SQL> select blocks from user_tables where table_name='T_BAK';
BLOCKS
----------
8
SQL> select dbms_rowid.rowid_block_number(rowid) blockno, count(*) from t_bak group by dbms_rowid.rowid_block_number(rowid);
BLOCKNO COUNT(*)
---------- ----------
86589 14
86588 14
86585 14
86586 14
86591 14
86590 14
86587 14
86592 1
8 rows selected
下面,我們來證明發生了行連結情況。
3、資料錶行連結檢驗
Analyze語句一度是非常流行的收集資料表統計量的操作方式。但是隨著dbms_stats包的成熟推廣,analyze在統計量收集方面的功能已經漸漸弱化。但是,Oracle依然保留了這個語句的兩個基本功能:對資料表進行行連結(Row Migration)檢測和索引健康程度檢測。
下面使用analyze語句進行資料表T的檢測。首先我們需要建立分析結果的容納資料表。
--呼叫ORACLE_HOME下的指令碼;
SQL> @?/rdbms/admin/utlchain.sql
Table created.
SQL> desc chained_rows;
Name Null? Type
----------------------------------------- -------- ----------------------------
OWNER_NAME VARCHAR2(30)
TABLE_NAME VARCHAR2(30)
CLUSTER_NAME VARCHAR2(30)
PARTITION_NAME VARCHAR2(30)
SUBPARTITION_NAME VARCHAR2(30)
HEAD_ROWID ROWID
ANALYZE_TIMESTAMP DATE
SQL> create public synonym chained_rows for chained_rows;
Synonym created.
SQL> grant all on chained_rows to public;
Grant succeeded.
分析資料表,如下:
--檢驗資料行Row Migration情況;
SQL> analyze table t list chained rows into chained_rows;
Table analyzed
Executed in 0.125 seconds
--發生Row Migration次數;
SQL> select count(*) from chained_rows;
COUNT(*)
----------
86
Executed in 0.016 seconds
SQL> select head_rowid from chained_rows where rownum<5;
HEAD_ROWID
------------------
AAASUCAABAAAU9hAAN
AAASUCAABAAAU9hAAO
AAASUCAABAAAU9hAAP
AAASUCAABAAAU9hAAQ
Executed in 0.016 seconds
SQL> select * from t where rowid='AAASUCAABAAAU9hAAQ';
OBJECT_ID VC
---------- --------------------------------------------------------------------------------
38 TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
Executed in 0.016 seconds
在99行記錄中,發生了86次行連結Row Migration情況。
4、結論
解決Oracle Row Migration的方法,就是進行資料表重構,重新對儲存結構和Rowid進行整理。我們說,在生產環境下,進行有預設值資料列的新增操作,會引起一系列的問題,要三思而行。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-742101/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Row Migration and Row Chaining(行遷移和行連結)AI
- 【轉載】行遷移和行連結(row chaining or row migration)AI
- 實驗:行遷移與分析語句 row migration and analyze statements
- 行連結(Row chaining)和行遷移(Row Migration)的讀書筆記AI筆記
- 遷移執行緒migration執行緒
- Laravel migration (資料庫遷移) 的使用Laravel資料庫
- 雲資料遷移(Cloud Data Migration,CDM)Cloud
- Oracle資料庫中資料行遷移與行連結Oracle資料庫
- Laravel 資料遷移給表新增註釋Laravel
- [Database Migration] 記一次未達預期的資料庫遷移Database資料庫
- 選出有行連線(row chain)或者是行遷移(row migeration)的表AI
- oracle效能診斷例項-row migration and row chainOracleAI
- Row Migration和row chainedAI
- Oracle 表空間資料檔案遷移Oracle
- ORACLE 資料遷移Oracle
- 【資料遷移】使用傳輸表空間遷移資料
- 使用RMAN進行Oracle資料庫遷移Oracle資料庫
- 使用RMAN執行oracle ASM資料遷移OracleASM
- ORACLE資料庫遷移Oracle資料庫
- 海量資料遷移之外部表並行抽取並行
- 資料表內容遷移?
- 海量資料處理_使用外部表進行資料遷移
- (個人)Oracle 表空間資料檔案遷移(轉)Oracle
- 資料遷移(1)——通過資料泵表結構批量遷移
- Oracle資料庫資料遷移流程Oracle資料庫
- AWS RDS Oracle資料遷移Oracle
- oracle 資料檔案遷移Oracle
- oracle遷移資料經驗Oracle
- oracle資料檔案遷移Oracle
- Oracle資料遷移參考Oracle
- MySQL 資料遷移Oracle工作MySqlOracle
- Oracle分割槽表遷移Oracle
- oracle 表遷移方法 (一)Oracle
- 資料庫-oracle-資料庫遷移資料庫Oracle
- oracle實驗記錄 (ROW 壓縮,遷移,連結)Oracle
- ORACLE表批量遷移表空間Oracle
- Oracle_遷移資料檔案Oracle
- Oracle 利用RMAN 完成資料遷移Oracle