上月通过在线重定义的方式对B2B库做了一次普通表转分区表的操作,涉及的表大小约为72G;听起来很玄乎,其实在线重定义的原理并不复杂:依据业务需求建立一张空的分区表(可以看成是中间表),接着将原表数据不断同步到中间表,同步完成后瞬间切换表名,中间表转正、原普通表离职。此方法的优点是可以保证业务的连续性,与此对应的代价是必须为中间表腾出足够的空间,例如在此案例中应准备至少72G的空间来迎接中间表,另外,别忘了索引。。。插播一句题外话,规划重于调整,尤其是对于大库,这一点尤为重要。
整个操作的具体步骤如下:
1. 加文件,准备足够的空间(包括数据表空间、索引表空间)
alter tablespace tbs_biz_scrab add datafile 'D:\U01\RWDATA\TBS_BIZ_SCRAB\TBS_BIZ_SCRAB13.DBF' size 8g autoextend off;
alter tablespace tbs_biz_scrab add datafile 'E:\U02\RWDATA\TBS_BIZ_SCRAB\TBS_BIZ_SCRAB14.DBF' size 8g autoextend off;
alter tablespace tbs_biz_scrab add datafile 'D:\U01\RWDATA\TBS_BIZ_SCRAB\TBS_BIZ_SCRAB15.DBF' size 8g autoextend off;
alter tablespace tbs_biz_scrab add datafile 'E:\U02\RWDATA\TBS_BIZ_SCRAB\TBS_BIZ_SCRAB16.DBF' size 8g autoextend off;
alter tablespace tbs_biz_scrab add datafile 'D:\U01\RWDATA\TBS_BIZ_SCRAB\TBS_BIZ_SCRAB17.DBF' size 8g autoextend off;
alter tablespace tbs_biz_scrab add datafile 'E:\U02\RWDATA\TBS_BIZ_SCRAB\TBS_BIZ_SCRAB18.DBF' size 8g autoextend off;
alter tablespace tbs_biz_scrab add datafile 'D:\U01\RWDATA\TBS_BIZ_SCRAB\TBS_BIZ_SCRAB19.DBF' size 8g autoextend off;
alter tablespace tbs_biz_scrab add datafile 'E:\U02\RWDATA\TBS_BIZ_SCRAB\TBS_BIZ_SCRAB20.DBF' size 8g autoextend off;alter tablespace tbs_index2 add datafile 'D:\U01\RWDATA\TBS_INDEX2\TBS_INDEX203.DBF' size 4g autoextend off;
alter tablespace tbs_index2 add datafile 'E:\U02\RWDATA\TBS_INDEX2\TBS_INDEX204.DBF' size 4g autoextend off;
alter tablespace tbs_index2 add datafile 'D:\U01\RWDATA\TBS_INDEX2\TBS_INDEX205.DBF' size 4g autoextend off;
alter tablespace tbs_index2 add datafile 'E:\U02\RWDATA\TBS_INDEX2\TBS_INDEX206.DBF' size 4g autoextend off;
alter tablespace tbs_index2 add datafile 'D:\U01\RWDATA\TBS_INDEX2\TBS_INDEX207.DBF' size 4g autoextend off;
alter tablespace tbs_index2 add datafile 'E:\U02\RWDATA\TBS_INDEX2\TBS_INDEX208.DBF' size 4g autoextend off;
2. 使用数据泵导出备份b2b_scrabdata表(谨慎。。。以防不测-_-||)
expdp b2b/******* DIRECTORY=B2B_DUMP DUMPFILE=20091016_b2b_scrabdata.dmp TABLES=b2b_scrabdata PARALLEL=1 LOGFILE=20091016_b2b_scrabdata.log;
3. 依据原表及业务需求建立中间表
CREATE TABLE temp_scrabdata PARTITION BY RANGE (scrabid)
(PARTITION P001 VALUES LESS THAN (501) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P002 VALUES LESS THAN (1001) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P003 VALUES LESS THAN (1501) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P004 VALUES LESS THAN (2001) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P005 VALUES LESS THAN (2501) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P006 VALUES LESS THAN (3001) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P007 VALUES LESS THAN (3501) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P008 VALUES LESS THAN (4001) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P009 VALUES LESS THAN (4501) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P010 VALUES LESS THAN (5001) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P011 VALUES LESS THAN (5501) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P012 VALUES LESS THAN (6001) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P013 VALUES LESS THAN (6501) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P014 VALUES LESS THAN (7001) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P015 VALUES LESS THAN (7501) TABLESPACE TBS_BIZ_SCRAB,
PARTITION P016 VALUES LESS THAN (MAXVALUE) TABLESPACE TBS_BIZ_SCRAB)
AS SELECT * FROM b2b_scrabdata where 1=0;
建立中间表主键(注:主键和索引名在转换之后并不会切换,转换后的分区表将使用中间表的主键和索引名)
alter table temp_scrabdata
add constraint PK_NEW_SCRABDATA primary key (SCRABDATAID)
using index
tablespace tbs_index2;
建立中间表索引
create index IDX_NEW_SCRABDATA_SCRABID on temp_scrabdata(scrabid, scrabdataid) local tablespace tbs_index2;
create index IDX_NEW_SCRABDATA_SCRABIDNAME on temp_scrabdata(scrabid, bizname) local tablespace tbs_index2;
create index IDX_NEW_SCRABDATA_SCRABIDWEB on temp_scrabdata(scrabid, web_id) local tablespace tbs_index2;
create index IDX_NEW_SCRABDATA_NAME on temp_scrabdata(bizname) global tablespace tbs_index2;
4. 执行转换
验证原表主键是否完整
SQL> EXEC DBMS_REDEFINITION.CAN_REDEF_TABLE('B2B', 'B2B_SCRABDATA', DBMS_REDEFINITION.CONS_USE_PK);
PL/SQL 过程已成功完成。
确认转换前的表信息
select * from user_tab_partitions where table_name='TEMP_SCRABDATA';
select * from user_tab_partitions where table_name='B2B_SCRABDATA';
执行转换
SQL> exec dbms_redefinition.start_redef_table('B2B','B2B_SCRABDATA','TEMP_SCRABDATA');
PL/SQL 过程已成功完成。
结束转换完成同步
SQL> exec dbms_redefinition.finish_redef_table('B2B','B2B_SCRABDATA','TEMP_SCRABDATA');
PL/SQL 过程已成功完成。
确认转换后的表信息
select * from user_tab_partitions where table_name='TEMP_SCRABDATA';
select * from user_tab_partitions where table_name='B2B_SCRABDATA';
5. 补充:如何split分区
执行split
alter table part_scrabdata
split partition P016 at(8001)
into (partition P016 TABLESPACE TBS_PART, partition P017 TABLESPACE TBS_PART)
update indexes; --避免索引失效
确认split后的索引状态
select index_name,partition_name,status from user_ind_partitions;
select index_name, status from user_indexes where index_name='PK_TEMP_SCRABDATA';
select constraint_name, status from user_constraints where index_name='PK_TEMP_SCRABDATA';
(注:建议提前预估数据量增长曲线,尽量在MAXVALUE分区有新数据之前完成split,以降低开销)
72G……存了上亿条了?
Paul —— 2009年11月17日@23:00
恩,最近几个月数据抓得比较猛。。。不分的话,整理的那个存过有点撑不住了。。。转换大概跑了4小时,不过当时无并发
老杨 —— 2009年11月17日@23:30
冬至啦,小小来送饺子啦
小小 —— 2009年12月22日@21:15
跪谢师傅,哈哈
老杨 —— 2009年12月24日@08:58