在线表重定义完毕以后,可以将表回滚到重定义之前的状态,同时保留所有对表做的DML操作。
有些情况下,你想回滚重定义的表。比如在重定义完之后,你发现表上的操作效率比之前更加糟糕,这时就可以通过回滚到重定义之前的状态。回滚在线表重定义主要用于当重定义改变了表的存储结构,并且这些改变导致了出乎预期的更坏的结果。
DBMS_REDEFINITION包的ROLLBACK过程将表置成重定义之前的初始状态,并且保留了DML的变更。
为了能用到ROLLBACK存储过程,在表的在线重定义过程中就需要启用rollback参数。如果你决定保留在线重定义的变更,则可以执行ABORT_ROLLBACK过程。
将表从非压缩表空间迁移到压缩表空间 
登录数据库pdb12c
1 2 3 4 5 6 7 8 9 10 sys@ORA12C> show pdbs;     CON_ID CON_NAME                       OPEN MODE  RESTRICTED ---------- ------------------------------ ---------- ----------          2 PDB$SEED                       READ ONLY  NO          3 PDB12C                         READ WRITE NO          4 PDB4                           READ WRITE NO sys@ORA12C> conn xb/xb@pdb12c Connected. 
新建两个表空间,一个未压缩,一个为压缩属性
1 2 create tablespace tbs_nocomp datafile 'tbs_nocomp.dbf' size 20m online; create tablespace tbs_comp default row store compress advanced datafile 'tbs_comp.dbf' size 20m online; 
创建相关表
1 2 3 4 5 6 7 8 9 10 11 -- 原始表 create table tab_rollback( id number(4) primary key, name varchar2(20)) tablespace tbs_nocomp; -- 中间表 create table mid_tab_rollback( id number(4) primary key, name varchar2(20)) tablespace tbs_comp; 
开始在线重定义,确保enable_rollback参数为TRUE,这样重定义中间的操作才能被回滚
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 BEGIN  DBMS_REDEFINITION.START_REDEF_TABLE(  uname => 'XB',  orig_table => 'TAB_ROLLBACK',  int_table => 'MID_TAB_ROLLBACK',  options_flag => DBMS_REDEFINITION.CONS_USE_PK,  enable_rollback => TRUE);  END;  / -- 复制依赖对象 DECLARE  num_errors PLS_INTEGER; BEGIN  DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(  uname => 'XB',  orig_table => 'TAB_ROLLBACK',  int_table => 'MID_TAB_ROLLBACK',  copy_indexes => DBMS_REDEFINITION.CONS_ORIG_PARAMS,  copy_triggers => TRUE,  copy_constraints => TRUE,  copy_privileges => TRUE,  ignore_errors => TRUE,  num_errors => num_errors);  END; / 
查询DBA_REDEFINITION_ERRORS视图检查是否有报错,主键和索引的相关错误可忽略
1 2 3 4 5 6 7 8 9 10 11 12 13 SET LONG 8000 SET PAGES 8000 COLUMN OBJECT_NAME HEADING 'Object Name' FORMAT A20 COLUMN BASE_TABLE_NAME HEADING 'Base Table Name' FORMAT A20 COLUMN DDL_TXT HEADING 'DDL That Caused Error' FORMAT A80 SELECT OBJECT_NAME, BASE_TABLE_NAME, DDL_TXT FROM DBA_REDEFINITION_ERRORS; Object Name          Base Table Name      DDL That Caused Error -------------------- -------------------- -------------------------------------------------------------------------------- SYS_C0010808         TAB_ROLLBACK         ALTER TABLE "XB"."MID_TAB_ROLLBACK" ADD CONSTRAINT "TMP$$_SYS_C00108080" PRIMARY                                            KEY ("ID")                                             USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255                                             TABLESPACE "TBS_NOCOMP"  ENABLE NOVALIDATE 
同步中间表MID_TAB_ROLLBACK
1 2 3 4 5 6 7 BEGIN DBMS_REDEFINITION.SYNC_INTERIM_TABLE( uname => 'XB', orig_table => 'TAB_ROLLBACK', int_table => 'MID_TAB_ROLLBACK'); END; / 
完成重定义操作
1 2 3 4 5 6 7 BEGIN DBMS_REDEFINITION.FINISH_REDEF_TABLE( uname => 'XB', orig_table => 'TAB_ROLLBACK', int_table => 'MID_TAB_ROLLBACK'); END; / 
在这最后一步过程中TAB_ROLLBACK表会被排他锁锁住,完成这一步操作以后,原表TAB_ROLLBACK将会具有所有中间表MID_TAB_ROLLBACK的特性,这时其就会处于压缩表空间下存储。
1 2 3 4 5 xb@PDB12C> select tablespace_name from user_tables where table_name='TAB_ROLLBACK'; TABLESPACE_NAME ------------------------------ TBS_COMP 
你可以定期的同步中间表MID_TAB_ROLLBACK,这会将对原重定义的表的DML操作同步到中间表当中去。当你定期同步中间表时,回滚操作则会变得更有效率,因为到时候对原表的DML操作肯定会更少。
1 2 3 4 5 6 7 BEGIN DBMS_REDEFINITION.SYNC_INTERIM_TABLE( uname => 'XB', orig_table => 'TAB_ROLLBACK', int_table => 'MID_TAB_ROLLBACK'); END; / 
如果表重定义完的结果符合预期,终止回滚保留重定义带来的变化,然后清理那些用于回滚操作的数据库对象
1 2 3 4 5 6 7 BEGIN DBMS_REDEFINITION.ABORT_ROLLBACK( uname => 'XB', orig_table => 'TAB_ROLLBACK', int_table => 'MID_TAB_ROLLBACK'); END; / 
回滚在线重定义操作 
当最后发现表重定义完的结果不符合预期,则通过ROLLBACK过程回滚这些变化
1 2 3 4 5 6 7 8 9 10 11 12 13 BEGIN DBMS_REDEFINITION.ROLLBACK( uname => 'XB', orig_table => 'TAB_ROLLBACK', int_table => 'MID_TAB_ROLLBACK'); END; / xb@PDB12C> select tablespace_name from user_tables where table_name='TAB_ROLLBACK'; TABLESPACE_NAME ------------------------------ TBS_NOCOMP