公司的一张数据表数据量太大,为提高数据查询速度,对其进行在线重定义分区,网上查阅各路大神帖子,自我实验总结如下:
测试数据为一张4亿+多条数据量源表:TAB_SJ_SIGNAL_VALUE_61 ;
特点:表数据根据列 TIME 有明显的时间划分;
1--建中间表t3,手动创建分区,下面操作都是默认使用的中间表t3;
create table t3 partition by range(time) --创建中间表t3,按时间time分区;
(partition a1 values less than (to_date('2016/01/26','yyyy/mm/dd')) tablespace db_sj_61_v1, --分区a1
partition a2 values less than (to_date('2016/01/27','yyyy/mm/dd')) tablespace db_sj_61_v1, --分区a2
partition a3 values less than (to_date('2016/01/28','yyyy/mm/dd')) tablespace db_sj_61_v1,
partition a4 values less than (to_date('2016/01/29','yyyy/mm/dd')) tablespace db_sj_61_v1,
partition a5 values less than (maxvalue) tablespace db_sj_61_v1;
as select * from TAB_SJ_SIGNAL_VALUE_61 where 1=2; --表结构可以根据已有源表来直接引用;
其他说明:
1)分区a1,时间范围是小于2016/01/26的所有数据,使用的表空间db_sj_61_v1;
2)分区a2,存储的是26号全天数据,我这里使用了与a1同一个表空间,每个分区可以使用不同的表空间,读者可根据自己的实际情况决定;
3)分区a5,对于大于某个范围后的所有值,可以使用函数 maxvalue 来确定分区;
2--创建多通道,提高执行效率;
alter session force parallel dml parallel 8;
alter session force parallel query parallel 8;
alter session force parallel ddl parallel 4;
3--验证是否可行
begin
dbms_redefinition. can_redef_table('ADMIN1','TAB_SJ_SIGNAL_VALUE_61',dbms_redefinition.cons_use_rowid);
end;
说明: dbms_redefinition. can_redef_table ('用户名','源表',重定义方式(主键或Rowid))
4--执行重定义操作
begin
dbms_redefinition. start_redef_table('ADMIN1','TAB_SJ_SIGNAL_VALUE_61','t3',null,dbms_redefinition.cons_use_rowid);
end;
说明:dbms_redefinition. start_redef_table ('用户名','源表','中间表',映射关系(可选),方式(主键或Rowid) );
5--迁移关联数据,如索引、触发器等等
declare
num_errors pls_integer;
begin
dbms_redefinition.copy_table_dependent
测试数据为一张4亿+多条数据量源表:TAB_SJ_SIGNAL_VALUE_61 ;
特点:表数据根据列 TIME 有明显的时间划分;
1--建中间表t3,手动创建分区,下面操作都是默认使用的中间表t3;
create table t3 partition by range(time) --创建中间表t3,按时间time分区;
(partition a1 values less than (to_date('2016/01/26','yyyy/mm/dd')) tablespace db_sj_61_v1, --分区a1
partition a2 values less than (to_date('2016/01/27','yyyy/mm/dd')) tablespace db_sj_61_v1, --分区a2
partition a3 values less than (to_date('2016/01/28','yyyy/mm/dd')) tablespace db_sj_61_v1,
partition a4 values less than (to_date('2016/01/29','yyyy/mm/dd')) tablespace db_sj_61_v1,
partition a5 values less than (maxvalue) tablespace db_sj_61_v1;
as select * from TAB_SJ_SIGNAL_VALUE_61 where 1=2; --表结构可以根据已有源表来直接引用;
其他说明:
1)分区a1,时间范围是小于2016/01/26的所有数据,使用的表空间db_sj_61_v1;
2)分区a2,存储的是26号全天数据,我这里使用了与a1同一个表空间,每个分区可以使用不同的表空间,读者可根据自己的实际情况决定;
3)分区a5,对于大于某个范围后的所有值,可以使用函数 maxvalue 来确定分区;
2--创建多通道,提高执行效率;
alter session force parallel dml parallel 8;
alter session force parallel query parallel 8;
alter session force parallel ddl parallel 4;
3--验证是否可行
begin
dbms_redefinition. can_redef_table('ADMIN1','TAB_SJ_SIGNAL_VALUE_61',dbms_redefinition.cons_use_rowid);
end;
说明: dbms_redefinition. can_redef_table ('用户名','源表',重定义方式(主键或Rowid))
4--执行重定义操作
begin
dbms_redefinition. start_redef_table('ADMIN1','TAB_SJ_SIGNAL_VALUE_61','t3',null,dbms_redefinition.cons_use_rowid);
end;
说明:dbms_redefinition. start_redef_table ('用户名','源表','中间表',映射关系(可选),方式(主键或Rowid) );
5--迁移关联数据,如索引、触发器等等
declare
num_errors pls_integer;
begin
dbms_redefinition.copy_table_dependent
(uname => 'ADMIN1',
orig_table => 'TAB_SJ_SIGNAL_VALUE_61',
int_table => 't3',
copy_indexes => 0,
copy_triggers => TRUE,
copy_constraints => FALSE,
copy_privileges => TRUE,
ignore_errors => FALSE,
num_errors => num_errors,
copy_statistics => FALSE);
orig_table => 'TAB_SJ_SIGNAL_VALUE_61',
int_table => 't3',
copy_indexes => 0,
copy_triggers => TRUE,
copy_constraints => FALSE,
copy_privileges => TRUE,
ignore_errors => FALSE,
num_errors => num_errors,
copy_statistics => FALSE);
END;
6--执行数据同步
begin
dbms_redefinition. sync_interim_table('ADMIN1','TAB_SJ_SIGNAL_VALUE_61','T3');
end;
7--完成重定义
begin
dbms_redefinition. finish_redef_table('ADMIN1','TAB_SJ_SIGNAL_VALUE_61','T3');
end;
*1--Oracle11g开始提供了自动创建分区的功能;
create table t4 partition by range(time) --仍然以时间为划分节点
interval(numtodsinterval (1,'hour')) --时间间隔设置为1小时
store in (db_sj_61_v2) --设置存储表空间db_sj_61_v2
(partition p0 valuse less than(to_date('2016/01/25 00:00:00','yyyy/mm/dd hh24:mi:ss'))) --初始分区p0
as select * from TAB_SJ_SIGNAL_VALUE_61 where 1=2;
详细说明:
6--执行数据同步
begin
dbms_redefinition. sync_interim_table('ADMIN1','TAB_SJ_SIGNAL_VALUE_61','T3');
end;
7--完成重定义
begin
dbms_redefinition. finish_redef_table('ADMIN1','TAB_SJ_SIGNAL_VALUE_61','T3');
end;
*1--Oracle11g开始提供了自动创建分区的功能;
create table t4 partition by range(time) --仍然以时间为划分节点
interval(numtodsinterval (1,'hour')) --时间间隔设置为1小时
store in (db_sj_61_v2) --设置存储表空间db_sj_61_v2
(partition p0 valuse less than(to_date('2016/01/25 00:00:00','yyyy/mm/dd hh24:mi:ss'))) --初始分区p0
as select * from TAB_SJ_SIGNAL_VALUE_61 where 1=2;
详细说明:
1)在做完实验后,发现按天划分每个分区里的数据量依然很大,遂决定按小时进行自动分区,其他步骤都一样;
2)注意函数numtodsinterval作用的范围是:second to day 秒级-天级别(eg:second/minute/hour/day);
与numtodsinterval函数类似numtoyminterval,作用范围为year to month年-月级别数据(eg:month/year);
3)store in (tbs1,tbs2,...)这里可以设置多个存储的表空间,以逗号隔开即可;
4)初始分区p0,设置存放初始时间之前的所有数据,后面时间的分区交给系统自动创建;
***************************
--查询重定义后的结果,可分别查询源表与中间表,数据有问题时甚至可以通过改名互换解决;
SQL> select partition_name,high_value,tablespace_name
2 from user_tab_partitions where table_name='TAB_SJ_SIGNAL_VALUE_61'
3 order by partition_position;
--检查重定义后索引信息的存在与否
SQL> select index_name,index_type,table_owner,table_name
2 from user_indexes where table_name = 'TAB_SJ_SIGNAL_VALUE_61';
2)注意函数numtodsinterval作用的范围是:second to day 秒级-天级别(eg:second/minute/hour/day);
与numtodsinterval函数类似numtoyminterval,作用范围为year to month年-月级别数据(eg:month/year);
3)store in (tbs1,tbs2,...)这里可以设置多个存储的表空间,以逗号隔开即可;
4)初始分区p0,设置存放初始时间之前的所有数据,后面时间的分区交给系统自动创建;
***************************
--查询重定义后的结果,可分别查询源表与中间表,数据有问题时甚至可以通过改名互换解决;
SQL> select partition_name,high_value,tablespace_name
2 from user_tab_partitions where table_name='TAB_SJ_SIGNAL_VALUE_61'
3 order by partition_position;
--检查重定义后索引信息的存在与否
SQL> select index_name,index_type,table_owner,table_name
2 from user_indexes where table_name = 'TAB_SJ_SIGNAL_VALUE_61';