1. 程式人生 > >Oracle dbms_redefinition線上重定義表結構

Oracle dbms_redefinition線上重定義表結構

 剛接手一套系統應用資料庫,因為專案建設期間種種原因,庫是非歸檔模式也沒有備份,更讓我無語的是有個表增長的比較快,將近90G大小,每隔一段時間都要刪除前三個月以前的資料,然後再用shrink收縮空間,因為是非分割槽表,shrink很是浪費時間,而且很多時間無法正常完成shrink操作,想將它改成分割槽表,同時業務部門又允許停資料庫,只能利用ORACLE 10g的一個新特性,DBMS_REDEFINITION包線上轉換成分割槽表,然後將以前的分割槽直接truncate掉,這樣以前幾個小時才能完成的工作,1分鐘內就可以搞定,具體操作過程如下。

    操作環境說明:ORACLE 10G 10.2.0.4,

HP-UNIX系統

    DBMS_REDEFINITION包支援線上對錶結構進行重定義,包括新增、刪除列等操作,整個操作過程中只在資料同步時對原表臨時進行加鎖處理,基本上可以忽略對業務的影響,特別是對於銀行、電信行業非RAC環境使用DBMS_REDEFINITION對錶行DDL修改是一種非常不錯的選擇。

    在這裡我們只用DBMS_REDEFINITION對非區表完成分割槽轉換,具體使用方法如下:

第一步:選擇轉換方法

    有兩種選擇,一種是建立主鍵,我的生產環境沒有主鍵,那麼我們只能選擇rowid這種方法

第二步:檢查表是否可以重定義

begin   DBMS_REDEFINITION.CAN_REDEF_TABLE(uname        =>'orabpel',                                     tname        =>'AUDIT_TRAIL',                                     options_flag => dbms_redefinition.cons_use_rowid

); end; 說明:如果此不可重定義,直接會報不能重定義的原因,如果可以重定義,提示PL/SQL執行完成,紅色選項是可選項,預設是按主鍵方法進行轉換,因我操作的環境沒有主鍵,那麼只能選擇rowid這種方法

第三步:建立轉換臨時表

dbms_redefinition線上重定義表結構 說明:因10g不支援間隔分割槽,只能通過手工進行建立分割槽,圖片只顯示了部分內容,下面基本上一樣,需要注意日期的寫法,同時要注意分割槽只能將小的日期放在前面,大的放在後面,否則會報ORA-14037分割槽"AUDIT_TRAIL"分割槽界限過高!第四步:設定並行操作

alter session force parallel dml parallel 4; alter session force parallel query parallel 4;

因為我的表是90G,比較大,為加快處理速度設定並行執行,如果表比較小,這一步可以不要!

第五步:開始重定義表結構

BEGIN   DBMS_REDEFINITION.START_REDEF_TABLE(uname       => 'orabpel',                                       orig_table  => 'AUDIT_TRAIL',                                       int_table   => 'AUDIT_TRAIL_EMP',                                      options_flag => dbms_redefinition.cons_use_rowid

                                      ); --紅色部分容易忽略 END;

注意:此過程比較消耗時間,會把中間表填滿資料,所以此時要有足夠的空間產生新中間表資料

第六步:同步臨時表

BEGIN   DBMS_REDEFINITION.SYNC_INTERIM_TABLE(uname      => 'orabpel',                                        orig_table => 'AUDIT_TRAIL',                                        int_table  => 'AUDIT_TRAIL_EMP'                                        ); END;

--此過程比較快,只是同步從開始轉換到現在產生的新資料

第七步:完成重定義

BEGIN   DBMS_REDEFINITION.FINISH_REDEF_TABLE(uname      => 'orabpel',                                        orig_table => 'AUDIT_TRAIL',                                        int_table  => 'AUDIT_TRAIL_EMP'                                        ); END;第八步:刪除臨時表

BEGIN

  truncate table AUDIT_TRAIL_EMP;--大表不要忘記這步操作哦   drop table AUDIT_TRAIL_EMP; --刪除臨時表的定義

END;

如果順利的話到此就結束了,原表變成了分割槽表,在沒有停業務的情況下完成了表的線上重定義,但是操作過程中往往沒那麼順利,執行過程中報錯怎麼處理呢?

第九步:異常情況下終止操作

BEGIN

  DBMS_REDEFINITION.ABORT_REDEF_TABLE(uname      => 'orabpel',                                       orig_table => 'AUDIT_TRAIL',                                       int_table  => 'AUDIT_TRAIL_EMP'                                       );  END;

在執行任何一步出錯,都可以執行第九步終止轉換操作!

第十步:檢查驗證有效性

 做完以後一定要檢查是否有失效對像

 select * from dba_objects where status<>'VALID' and owner='orabpel';

 發現有失效的包 ,處理方法

alter package orabpel.collxa compile;

處理完失效對像後檢視最後一個分割槽的資料是否在增長,驗證轉換後分區是否可用

 select count(*) from orabpel.audit_trail_1309;

 發現數據並沒有增長,肯定是那裡出了問題,然後檢視alert.log是否有報錯

 發現報錯如下:

    Some indexes or index [sub]partitions of table ORABPEL.AUDIT_TRAIL have been marked unusable

    處理方法如下:

SELECT 'ALTER INDEX ' || INDEX_OWNER || '.' || INDEX_NAME ||        'REBUILD PARTITION ' || PARTITION_NAME || ' NOLOGGING online;'   FROM DBA_IND_PARTITIONS  WHERE INDEX_OWNER NOT IN ('SYS', 'SYSTEM', 'PUBLIC')    AND STATUS = 'UNUSABLE'  UNION ALL   SELECT 'alter index ' || OWNER || '.' || A.INDEX_NAME ||        ' REBUILD online nologging;'   FROM DBA_INDEXES A  WHERE OWNER NOT IN ('SYS', 'SYSTEM', 'PUBLIC')    AND STATUS = 'UNUSABLE';

 跟據執行結果執行,否則資料將不能正常寫入,(切記!)

 alter index ORABPEL.CS_PK1 REBUILD online nologging;

再次查詢分割槽表資料是否正常寫入

   select count(*) from orabpel.audit_trail;

 發現數據增長很快,至此操作驗證成功!

   總結:線上重定義並不能100%保證不影響業務,我在測試庫上發現不影響業務,但是在正式庫操作完以報最新分割槽表資料並沒有增加,alert.log報上面的錯誤,處理完以後資料才正常寫入,因此操作完以後一定要記得檢視dba_objects去及時處理失效對像,同時檢視alert.log是否有異常資訊及時進行相應的處理,最後一定要驗證最後一個分割槽表資料是否在增長,只能這樣我們才能確認我們轉換後的分割槽表是可用的!特別需要注意的是,如果你的庫是10g的庫,一定要及時增加分割槽,因為10g不支援間隔分割槽,需要人為手工的及時新增新的分割槽,如果在11g裡面間隔分割槽可以做到自動新增新的分割槽,但是看錶的DDL語句時發現並沒有隔間分割槽的關鍵字,這就是為什麼同樣的語句在10g需要手工新增分割槽,而在11g卻可以自動增加分割槽的原因。不知道為什麼11g中間隔分割槽表DDL語句看不到間隔分割槽關鍵字,知道的朋友可以QQ交流一下