目前项目中有一个问题,存在一个分区表,因为分区规则的问题,使得分区表中的数据分布很不均匀,数据都分区在了默认的maxvalue分区上。现在需要重新划分分区。从常规的角度来看,这中重新分区的问题一般有以下几个步骤。
1.数据备份,采用exp/expdp或者ctas的方式
2.truncate 分区表的数据
3.删除多余的分区,只保留maxvalue的分区
4.使用split partition进行分区
5.使用开始的数据备份,把数据导入。
对于这个问题,如果采用这种方式,势必会需要一定的downtime,如何尽可能保持数据访问的高可用性呢,这个时候可以考虑一下分区表的在线重定义,即重新定义一个分区表,把这两个分区表的ddl进行交换。
我们来简单做一个测试。
创建一个测试表,只含有一个maxvalue分区,然后创建对应的索引。
CREATE TABLE tab_part_one_par
(
col1 varchar2(30),
col2 DATE
)
partition BY range(col2)
(
partition tab_part_maxvalue values less than (maxvalue)
);
create index inx_part_one_par on tab_part_one_par(col2) local;
然后尝试插入一些数据。
INSERT INTO tab_part_one_par(col1, col2) SELECT -1, sysdate-365 FROM dual;
INSERT INTO tab_part_one_par(col1, col2) SELECT 0, sysdate FROM dual;
INSERT INTO tab_part_one_par(col1, col2) SELECT +1, sysdate+360 FROM dual;
commit;
这个时候查看数据的情况。
SQL> SELECT col1,to_char(col2,'yyyy-mm-dd') FROM tab_part_one_par;
COL1 TO_CHAR(CO
------------------------------ ----------
-1 2014-07-15
0 2015-07-15
1 2016-07-09
3 rows selected.
接着我们创建另外一个分区表,这个分区表中的分区规则是对的
CREATE TABLE tab_part
(
col1 varchar2(30),
col2 DATE
)
partition BY range(col2)
(
partition tab_part_2014 VALUES less than (to_date('2014-08-01','yyyy-mm-dd')),
partition tab_part_2015 VALUES less than (to_date('2015-08-01','yyyy-mm-dd')),
partition tab_part_2016 VALUES less than (to_date('2016-08-01','yyyy-mm-dd')),
partition tab_part_maxvalue values less than (maxvalue)
);
CREATE INDEX INX_PART ON tab_part(COL2) LOCAL;
然后我们开始使用在线重定义的方式。
首先验证表是否可以在线重定义
n1@TEST11G> EXEC dbms_redefinition.can_redef_table('N1','TAB_PART_ONE_PAR',1);
BEGIN dbms_redefinition.can_redef_table('N1','TAB_PART_ONE_PAR',1); END;
*
ERROR at line 1:
ORA-12089: cannot online redefine table "N1"."TAB_PART_ONE_PAR" 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
因为分区表中我们定义的是local index,所以创建的唯一性索引不是主键,为了使得这个问题能够顺利处理,我们可以考虑使用rowid
EXEC dbms_redefinition.can_redef_table('N1','TAB_PART_ONE_PAR',dbms_redefinition.cons_use_rowid);
然后我们调用dbms_redefiniton的三个方法,依次处理。
exec DBMS_REDEFINITION.CAN_REDEF_TABLE('N1','TAB_PART_ONE_PAR',2);
exec DBMS_REDEFINITION.START_REDEF_TABLE('N1','TAB_PART_ONE_PAR','TAB_PART',NULL,2);
exec DBMS_REDEFINITION.FINISH_REDEF_TABLE('N1','TAB_PART_ONE_PAR','TAB_PART');
过程很简单,我们来简单验证一下在线重定义的效果。
SELECT * FROM TAB_PART_ONE_PAR partition (TAB_PART_2014);
COL1 COL2
------------------------------ ------------------
-1 15-JUL-14
SQL> SELECT * FROM TAB_PART_ONE_PAR partition (TAB_PART_2015);
COL1 COL2
------------------------------ ------------------
0 15-JUL-15
SQL>
SQL> SELECT * FROM TAB_PART_ONE_PAR partition (TAB_PART_2016);
COL1 COL2
------------------------------ ------------------
1 09-JUL-16
可以看到数据已经都同步到三个指定的分区里了。从这个过程来看,效果有点类似exchange partition的效果。但是实现方式还是有很大的不同。
通过这个例子可以看到分区表之间也可以很方便的使用在线重定义来处理,不过需要额外考虑的因素就是权限的分配。