Oracle从9i版本开始提供了在线重定义表功能,通过调用DBMS_REDEFINITION包,可以在修改表结构的同时允许DML操作。
在线重定义表具有以下功能:
1 修改表的存储参数
2 可以将表转移到其他表空间
3 增加并行查询选项
4 增加或删除分区
5 重建表以减少碎片
6 将堆表改为索引组织表或相反的操作
7 增加或删除一个列
调用DBMS_REDEFINITION包需要EXECUTE_CATALOG_ROLE角色和以下权限:
CREATE ANY TABLE
ALTER ANY TABLE
DROP ANY TABLE
LOCK ANY TABLE
SELECT ANY TABLE
1.在线重定义的方法
方法一:基于主键。要求原表和重定义后的表有相同的主键列。这是默认方法!
方法二:基于ROWID。该方法不能用于索引组织表(IOT),并且在重定义的表中会添加隐藏列(M_ROW$$),建议将该列标记为unused或删除。
ALTER TABLE TABLE_NAME SET UNUSED (M_ROW$$);
ALTER TABLE TABLE_NAME DROP UNUSED COLUMNS;
2 使用dbms_redefinition.can_redef_table(),检查原表是否支持进行在线重定义。
如果表中没有主键,则检查失败!
YANG@yangdb> EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(user, 'T1', DBMS_REDEFINITION.CONS_USE_PK);
BEGIN DBMS_REDEFINITION.CAN_REDEF_TABLE(user, 'T1', DBMS_REDEFINITION.CONS_USE_PK); END;
*
ERROR at line 1:
ORA-12089: cannot online redefine table "YANG"."T1" with no primary key
ORA-06512: at "SYS.DBMS_REDEFINITION", line 139
ORA-06512: at "SYS.DBMS_REDEFINITION", line 1782
ORA-06512: at line 1
YANG@yangdb> alter table t1 add primary key(id);
Table altered.
YANG@yangdb> EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(user, 'T1', DBMS_REDEFINITION.CONS_USE_PK);
PL/SQL procedure successfully completed.
创建测试表rbol
YANG@yangdb> create table rbol (id number primary key,time date);
Table created.
YANG@yangdb> insert into rbol select rownum ,created from dba_objects;
73987 rows created.
YANG@yangdb> commit;
Commit complete.
3 检查是否可以进行在线重定义!
YANG@yangdb> EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(user, 'RBOL', DBMS_REDEFINITION.CONS_USE_PK);
PL/SQL procedure successfully completed.
4 根据重定义后你期望得到的结构建立中间表。比如:采用分区表,删除或者增加字段等,创建中间表!
20:22:14 yang(45)@yangdb> create table rbol_tmp (id number primary key,time date,val varchar2(10));
Table created.
20:22:36 yang(45)@yangdb> EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE(user, 'RBOL', DBMS_REDEFINITION.CONS_USE_PK);
PL/SQL procedure successfully completed.
20:22:53 yang(45)@yangdb> exec dbms_redefinition.start_redef_table(user,'RBOL','RBOL_TMP');
PL/SQL procedure successfully completed.
5 在重定义过程中对原表rbol进行dml操作
20:24:39 yang(32)@yangdb> delete from rbol where rownum < 10;
9 rows deleted.
20:24:44 yang(32)@yangdb> select count(1) from rbol;
COUNT(1)
----------
73479
1 row selected.
Elapsed: 00:00:00.00
20:24:49 yang(32)@yangdb> select count(1) from rbol_tmp;
COUNT(1)
----------
73488
1 row selected.
20:25:43 yang(32)@yangdb> commit;
Commit complete.
6 如果在执行DBMS_REDEFINITION.START_REDEF_TABLE()过程和执行DBMS_REDEFINITION.FINISH_REDEF_TABLE()过程直接在重定义表上执行了大量的DML操作,那么可以选择执行一次或多次的SYNC_INTERIM_TABLE()过程,以减少最后一步执行FINISH_REDEF_TABLE()过程时的锁定时间。
20:25:55 yang(32)@yangdb> exec dbms_redefinition.sync_interim_table(user,'RBOL','RBOL_TMP');
PL/SQL procedure successfully completed.
20:26:06 yang(32)@yangdb> select count(1) from rbol_tmp;
COUNT(1)
----------
73479
1 row selected.
20:26:13 yang(32)@yangdb> select count(1) from rbol;
COUNT(1)
----------
73479
1 row selected.
7 结束重定义步骤!
20:25:25 yang(45)@yangdb> exec dbms_redefinition.finish_redef_table(user,'RBOL','RBOL_TMP');
PL/SQL procedure successfully completed.
20:26:43 yang(32)@yangdb> desc rbol
Name Null? Type
------ ------- --------
ID NOT NULL NUMBER
TIME DATE
VAL VARCHAR2(10)