使用DBMS_REDEFINITION包執行線上重定義表(ONLINE TABLE REDEFINITION)

尛樣兒發表於2015-08-07

   這篇文章參考官方文件,簡單討論一下使用DBMS_REDEFINITION包執行線上重定義表。線上重定義表技術是從9i開始就出現的技術,該技術可以有效的減少對錶邏輯結構和物理結構的調整給業務系統帶來的影響,在對某個表做線上重定義操作的過程並不影響對原表的查詢和DML操作,只是在結束線上重定義操作的時候會對原表有短暫的鎖定。線上重定義和傳統方法相比,增強了資料庫的可用性。對錶的線上重定義由於要產生中間表,所以要求剩餘至少和原表空間相同,甚至更大。線上重定義功能實際是透過物化檢視來實現的。我們可以使用OEM或者DBMS_REDEFINITION包完成線上重定義操作。

線上表重定義可以達到以下的目的:
1).修改表或叢集的儲存引數。
2).移動表或叢集到不同的表空間。
3).增加,修改或者DROP表或叢集的一個或多個欄位。
4).改變分割槽結構。
5).改變單一表分割槽的物理屬性,包括一定它到相同使用者的不同表空間下。
6).改變物化檢視日誌的物理屬性或者Oracle Streams高階佇列佇列表。
7).新增並行查詢支援。
8).重建表或者叢集減少碎片,在很多情況下,線上段shrink是減少碎片更容易的方法。
9).將普通錶轉換為IOT,或者將IOT轉換為普通表。
10).轉換一個相關表到表的物件欄位,或者反向轉換。
11).轉換一個物件表到相關的表或者表的物件欄位,或者反向轉換。


普通使用者要想使用DBMS_REDEFINITION包,需要擁有以下許可權:

EXECUTE_CATALOG_ROLE角色。
CREATE ANY TABLE.
ALTER ANY TABLE.
DROP ANY TABLE.
LOCK ANY TALBE.
SELECT ANY TABLE.

執行COPY_TABLE_DEPENDENTS過程還需要以下許可權:
CREATE ANY TRIGGER.
CREATE ANY INDEX.

下面討論一下使用DBMS_REDEFINITION包執行線上重定義表的步驟:

1.選擇重定義方法:by key或者by rowid

    By key,選擇主鍵或者所有欄位有NOT NULL約束的唯一鍵用於線上重定義操作。使用這種方法,線上重定義之前和之後表應該有相同的主鍵欄位,這是線上重定義操作默認和優先選擇的方法。

    By rowid,如果沒有主鍵可以使用這種方法,使用這種方法,隱藏欄位M_ROW$$被新增到重定義後的表中。推薦在重定義表之後將這個欄位DROP掉,或者將其標記為UNUSED。如果COMPATIBLE初始化引數設定為10.2.0或者更高,最終線上重定義的語法將自動設定這個欄位為UNUSED。可以使用ALTER TABLE ... DROP UNUSED COLUMNS語句DROP掉它。不能在索引組織表(IOT)上使用該方法。

2.驗證表是否能被線上重定義。

   透過呼叫CAN_REDEF_TABLE過程驗證表是否能被線上重定義。如果表不能作為線上重定義表的候選表,那麼這個過程提示一個錯誤,並且會表明為什麼該表不能線上重定
義。

3.建立一個空的中間表。

   按照期望的邏輯和物理屬性在線上重定義的表相同的使用者下建立一個空的中間表,如果要DROP欄位,那麼在中間表中不要包含它們,如果是新增加欄位,那麼在中間表中
新增這些欄位,如果是修改欄位,那麼在中間表按照想要的結果修改它們。

建立中間表不是必須按照重定義的表建立所有的索引,約束,授權,和觸發器。因為這些物件可以在下面的複製依賴物件的步驟中可以被自動定義。

4.啟動行遷移功能。

   如果採用rowid的方法重定義一個分割槽表,啟用中間表的行遷移功能。

ALTER TABLE ... ENABLE ROW MOVEMENT.

5.啟用會話並行功能。

    這是可選的步驟,如果重定義一張大表,想透過並行方式提升下面步驟的效能,執行以下的語句:
ALTER SESSION FORCE PARALLEL DML PARALLEL <degree-of-parallelism>;
ALTER SESSION FORCE PARALLEL QUERY PARALLEL <degree-of-parallelism>;

6.開始線上重定義過程。

提供以下的資訊呼叫START_REDEF_TABLE過程開始重定義過程:

>被線上重定義的使用者名稱和表名。
>中間表名稱。
>欄位對映字串,對映被重定義表的欄位到中間表的欄位。
>重定義方法。
 DBMS_REDEFINITION.CONS_USE_PK代表by key方法,這也是預設的方法。
 DBMS_REDEFINITION.CONS_USE_ROWID代表by rowid方法。
>在排序行中使用的欄位。
>如果重定義的分割槽表只有一個分割槽,分割槽名。

 因為這步會複製資料,所以可能會持續一段時間,表在被重新定義的整個過程中,查詢和DML操作仍然是可執行的。

注意:如果START_REDEF_TABLE以為某種原因失敗,必須呼叫ABORT_REDEF_TABLE過程,否則接下來重新定義表將失敗。

7.複製依賴的物件。

   重被重定義的表中複製依賴的物件(例如,觸發器,索引,物化檢視日誌,授權和約束)和統計資訊到中間表,使用以下兩種方法的其中一種,方法一是首選的方法,因
為它是自動的,該方法也會複製統計資訊到中間表。

>方法一:自動建立依賴物件
    使用COPY_TABLE_DEPENDENTS過程自動建立中間表的依賴物件,這個過程也叫做註冊依賴物件。在重定義過程完成後,依賴物件的名字將和原有名字保持一致。

>方法二:手動建立依賴物件
    可以手動建立中間表的依賴物件,並且註冊它們。

8.完成線上重定義過程。

   執行FINISH_REDEF_TABLE過程完成重定義表過程。在這個過程中,原始表將以排他模式被鎖定非常短的時間,時間長短依賴於原始表中獨立的(與中間表的資料差)資料
量,然而,FINISH_REDEF_TABLE在完成重定義之前將等待所有的DML操作提交。

9.處理M_ROW$$欄位。

   如果使用rowid線上重定義,並且COMPATIBLE初始化引數設定為10.1.0或者更低,DROP或者設定重定義後的表中出現的M_ROW$$隱藏欄位為UNUSED。

ALTER TABLE table_name set UNUSED(M_ROW$$);

   如果COMPATIBLE初始化引數為10.2.0或者更高,當重定義完成該隱藏欄位將自動被設定為UNUSED。可以使用ALTER TABLE ... DROP UNUSED COLUMNS語句DROP該欄位。


10.DROP中間表。

等待任何針對中間表長時間執行的查詢完成,然後DROP中間表。


如果對活動的中間表查詢執行DROP操作,可能收到ORA-08103的錯誤("object no longer exists")。


下面透過例子說明線上重定義表的過程:

1.驗證表線上重定義的條件,使用主鍵方法進行線上重定義驗證:
BEGIN
  DBMS_REDEFINITION.CAN_REDEF_TABLE('hr','admin_emp',
      DBMS_REDEFINITION.CONS_USE_PK);
END;
/

2.建立中間表hr.int_admin_emp:
CREATE TABLE hr.int_admin_emp
        (empno      NUMBER(5) PRIMARY KEY,
         ename      VARCHAR2(15) NOT NULL,
         job        VARCHAR2(10),
         mgr        NUMBER(5),
         hiredate   DATE DEFAULT (sysdate),
         sal        NUMBER(7,2),
         deptno     NUMBER(3) NOT NULL,
         bonus      NUMBER (7,2) DEFAULT(1000))
     PARTITION BY RANGE(empno)
       (PARTITION emp1000 VALUES LESS THAN (1000) TABLESPACE admin_tbs,
        PARTITION emp2000 VALUES LESS THAN (2000) TABLESPACE admin_tbs2);

3.開始重定義過程。
BEGIN
  DBMS_REDEFINITION.START_REDEF_TABLE('hr', 'admin_emp','int_admin_emp',
       'empno empno, ename ename, job job, deptno+10 deptno, 0 bonus',
        dbms_redefinition.cons_use_pk);
END;
/

4.複製依賴物件(自動在hr.int_admin_emp表上建立觸發器,索引,物化檢視日誌,授權和約束)。
DECLARE
num_errors PLS_INTEGER;
BEGIN
  DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('hr', 'admin_emp','int_admin_emp',
   DBMS_REDEFINITION.CONS_ORIG_PARAMS, TRUE, TRUE, TRUE, TRUE, num_errors);
END;
/
注意:在這兒ignore_errors引數設定為TRUE,根據實際情況,部分錯誤可直接忽略。

5.查詢DBA_REDEFINITION_ERRORS試圖查詢錯誤:
SQL> select object_name, base_table_name, ddl_txt from
         DBA_REDEFINITION_ERRORS;
 
OBJECT_NAME   BASE_TABLE_NAME  DDL_TXT
------------- ---------------- ------------------------------
SYS_C005836   ADMIN_EMP        CREATE UNIQUE INDEX "HR"."TMP$
                               $_SYS_C0058360" ON "HR"."INT_A
                               DMIN_EMP" ("EMPNO")
 
SYS_C005836   ADMIN_EMP        ALTER TABLE "HR"."INT_ADMIN_EM
                               P" ADD CONSTRAINT "TMP$$_SYS_C
                               0058360" PRIMARY KEY

6.(可選),同步中間表。
BEGIN 
  DBMS_REDEFINITION.SYNC_INTERIM_TABLE('hr', 'admin_emp', 'int_admin_emp');
END;
/

7.完成重定義。
BEGIN
  DBMS_REDEFINITION.FINISH_REDEF_TABLE('hr', 'admin_emp', 'int_admin_emp');
END;
/

    hr.admin_emp將被以排他模式鎖定很短的時間,直到這步結束,之後hr.admin_emp被重定義完成,hr.admin_emp將有hr.int_admin_emp表的所有屬性。

8.等待任何針對中間表長時間執行的查詢結束,然後DROP中間表。


    另外,線上重定義表可以透過OEM非常容易的完成在TABLE頁面,選擇要重定義表的欄位,從Actions List中選擇Reorganize。
   使用傳統的表重定義方法可能遇到一些問題,可以參考文章《Oracle Database將普通錶轉換為分割槽表遇到的問題》:http://blog.itpub.net/23135684/viewspace-1753024/

    《使用DBMS_REDEFINITION線上重定義表普通表為分割槽表》:http://blog.itpub.net/23135684/viewspace-661756/


    本文節選自《Oracle Database Administrator's Guide 11g Release 2 (11.2) Part Number E25494-02》中的部分內容,更詳細的內容和例子請參考這篇文章和對DBMS_REDEFINITION包的解釋。

相關文章:
   《Moving表到新的段或者表空間http://blog.itpub.net/23135684/viewspace-1766480/

--end--

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

相關文章