在数据库系统中,偶尔需要修改表的物理或者逻辑结构,出于下面几个目的:
1、提高查询或者DML的性能
2、适应应用程序的改变
3、管理存储
online table redefinition 是Oracle 提供的一种在修改表结构时没有显著影响表可用性的一种机制。online table redefinition 比传统的表重新定义在可用性方面有了很大的提高。
当表是在线重定义时,在重定义的过程中可以同时查询和DML操作,表加独占模式的锁在一个很小的窗口,窗口大小依赖于表大小和重定义的复杂度,对用户来说是完全透明的。
表在线重定义需要的空间约等于表使用的空间,如果增加新列,需要更多的空间。
表在线重定义的方式:
1、 使用EM 的重组对象向导
2、 使用DBMS_REDEFINITION 包
Online Table Redefinition特点:
1、修改表或者聚簇的存储参数
2、将表或者聚簇移动到其他表空间
3、在表或聚簇中增加、修改、删除一列或多列
4、增加或者删除分区支持(仅非聚簇表)
5、改变分区结构
6、改变单个表分区的物理特性,包括在相同schema中移到不同的表空间
7、改变物化视图日志或者Oracle Streams Advanced Queueing 队列表的物理特性
8、添加支持并行查询
9、重建表或聚簇减少碎片
10、将常规表变更为索引组织表或者将索引组织表转换为常规表
11、将关系表转换为对象列的表或者反向操作
12、将对象表转换为关系表或者对象列的表,反之亦可
通过使用DBMS_REDEFINITION执行在线重定义
在线重定义表步骤如下:
1、选择重定义方法
基于主键:选一个主键或者伪主键用来重定义。伪主键是唯一键,有 not null 约束。此方式,表重定义前后的版本需要有相同的主键列。推荐使用基于主键的方式(默认方式)
基于rowid:如果没有可用的键值是使用此方法。重定义后,增加了一个隐藏列M_ROW$$ ,建议重定义完成后删除或者将该列设置为unused,若COMPATIBLE设置为10.2.0 或者更高,在重定义最后阶段自动设置为unused,也可使用ALTER TABLE
... DROP
UNUSED
COLUMNS将其删除。(对应索引组织表不能使用此方式)
2、调用CAN_REDEF_TABLE检验表是否可以在线重定义
3、创建一个空的临时表(和重定义的表在一个schema)并指定所有的物理和逻辑属性。如果删除了列,在临时表中不包含该列的定义信息,增加列,在临时表中增加列的定义信息,修改列时,在临时表中定义需要修改的参数。临时表不必创建索引、约束、授权、触发器,因为在第六步复制依赖对象时会定义。
4、(可选的)如果重定义的是大表并希望在下一步中提高性能可以并行执行,使用如下语句:
alter session force parallel dml parallel degree-of-parallelism;
alter session force parallel query paralleldegree-of parallelism;
5、调用START_REDEF_TABLE开始重定义,需提供如下信息:
重定义的表的表名及schema名
临时表名
列映射
重定义方法( DBMS_REDEFINITION.CONS_USE_PK、DBMS_REDEFINITION.CONS_USE_ROWID
),若未指定,默认是CONS_USE_PK
列排序(可选)
若个重定义的表是一个仅一个分区的分区表,指定分区名
注意:如果由于某种原因,START_REDEF_TABLE失败,需调用ABORT_REDEF_TABLE,不然后续尝试重定义表将会失败。
6、从定义表复制依赖对象(如:triggers, indexes, materialized view logs, grants, and constraints)和统计信息到临时表。
自动创建依赖对象 :COPY_TABLE_DEPENDENTS过程在临时表上自动创建、注册依赖对象
手动创建依赖对象
7、执行FINISH_REDEF_TABLE 完成表的重定义。在执行该过程中,原表加独占锁,锁时间依赖于表数据量。然而FINISH_REDEF_TABLE 需要等待所有挂起的DML提交后才完成重定义。
8、如果使用的是通过rowid重定义并且COMPATIBLE
设置是10.1.0或者更低,将隐藏列M_ROW$$ 删除或者设置为unused。
ALTER TABLE table_name SET UNUNSED(M_ROW$$);
如果COMPATIBLE
设置为10.2.0或更高,当重定义完成后隐藏列自动设置为UNUSED,可以通过ALTER TABLE ... DROP UNUSED COLUMNS语句删除该列。
9、等待针对临时表的所有长时间允许的查询结束,删除临时表。
示例如下:
原表:
SQL> desc xezf.reo_online_test;
Name Null? Type
----------------------------------------- -------- ----------------------------
PROD_ID NOT NULL NUMBER(6)
PROD_NAME VARCHAR2(200)
CP_ID NOT NULL NUMBER(3)
PROD_SELLING_PRICE NUMBER(6,2)
PROD_STATUS NOT NULL VARCHAR2(4)
PROD_DESC VARCHAR2(800)
PROD_OID VARCHAR2(40)
PROD_ALERTCOUNT NUMBER(4)
PROD_PY VARCHAR2(50)
CPREPORT_FLAG NUMBER(1)
CHECKTIME_BUSY NUMBER
CHECKTIME_IDLE NUMBER
TIME_ALARM DATE
ADVANCE NUMBER
PROD_TYPE NUMBER
PAY_URL VARCHAR2(100)
BALANCE_PERIOD NUMBER
BUY_MODE VARCHAR2(32)
SDK_PRICE NUMBER(6,2)
CP_VISIBLE NUMBER
INTERRELATE_PROD_ID NUMBER(6)
INTERRELATE_FLAG NUMBER
1、通过CAN_REDEF_TABLE检查表
SQL> exec DBMS_REDEFINITION.CAN_REDEF_TABLE('xezf','reo_online_test', DBMS_REDEFINITION.CONS_USE_PK);
PL/SQL procedure successfully completed.
2、建立临时表,表结构如下:
SQL> desc xezf.temp_online_test
Name Null? Type
----------------------------------------- -------- ----------------------------
PROD_ID NOT NULL NUMBER(6)
PROD_NAME VARCHAR2(250)
CP_ID NOT NULL NUMBER(5)
PROD_PY VARCHAR2(50)
DJ_TEST NUMBER
3、调用START_REDEF_TABLE开始重定义
SQL> exec DBMS_REDEFINITION.START_REDEF_TABLE('xezf', 'reo_online_test','temp_online_test','PROD_ID PROD_ID,PROD_NAME PROD_NAME,CP_ID CP_ID,PROD_PY PROD_PY,12 dj_test',dbms_redefinition.cons_use_pk);
PL/SQL procedure successfully completed.
4、从定义表复制依赖对象
SQL > variable num_errors number;
SQL> exec dbms_redefinition.COPY_TABLE_DEPENDENTS('xezf','reo_online_test','temp_ONLINE_TEST',dbms_redefinition.cons_orig_params ,true,true,true,true,num_errors);
5、执行FINISH_REDEF_TABLE 完成表的重定义
SQL> exec dbms_redefinition.FINISH_REDEF_TABLE('xezf','reo_online_test','temp_ONLINE_TEST');
PL/SQL procedure successfully completed.
6、查看重定义完成的表
SQL> desc xezf.reo_online_test
Name Null? Type
----------------------------------------- -------- ----------------------------
PROD_ID NOT NULL NUMBER(6)
PROD_NAME VARCHAR2(250)
CP_ID NOT NULL NUMBER(5)
PROD_PY VARCHAR2(50)
DJ_TEST NUMBER
7、删除临时表
DBMS_REDEFINITION涉及的过程后续介绍