os: centos 7.4
db: oracle 11.2.0.4
Oracle 提供的在线重定义一般用于普通大表到分区表的转换,只有在很短时间内表不可操作,大大增加了在线调整的可用性。
原表数据量多时会生成很多归档日志。
用户权限
执行 dbms_redefinition 需要一些必要的权限
create user scott2 identified by oracle
account unlock
default tablespace system
;
alter user scott2 quota unlimited on system;
grant create session to scott2;
grant create table to scott2;
grant create materialized view to scott2;
grant create trigger to scott2;
--sys user grant
grant execute on dbms_redefinition to scott2;
grant execute_catalog_role to scott2;
grant select on dba_redefinition_errors to scott2;
old table
-- drop table scott2.TMP_PART_DAY purge;
create table scott2.TMP_PART_DAY
(
id number(20) not null,
name varchar2(1000),
memo varchar2(1000),
create_time date
)
;
--创建主键
alter table scott2.TMP_PART_DAY add constraint pk_TMP_PART_DAY primary key (id) using index;
--全局索引
create index scott2.TMP_PART_DAY_n1 on scott2.TMP_PART_DAY (name);
--全局索引
create index scott2.TMP_PART_DAY_n2 on scott2.TMP_PART_DAY (memo) ;
insert into scott2.TMP_PART_DAY(id,name,memo,create_time) values(1,'a','a',to_date('2018-11-01','yyyy-mm-dd'));
insert into scott2.TMP_PART_DAY(id,name,memo,create_time) values(2,'b','b',to_date('2018-12-01','yyyy-mm-dd'));
insert into scott2.TMP_PART_DAY(id,name,memo,create_time) values(3,'c','c',to_date('2019-01-01','yyyy-mm-dd'));
insert into scott2.TMP_PART_DAY(id,name,memo,create_time) values(4,'d','d',to_date('2019-01-10','yyyy-mm-dd'));
insert into scott2.TMP_PART_DAY(id,name,memo,create_time) values(5,'e','e',to_date('2019-02-01','yyyy-mm-dd'));
insert into scott2.TMP_PART_DAY(id,name,memo,create_time) values(6,'f','f',to_date('2019-04-01','yyyy-mm-dd'));
commit;
模拟大数据量
truncate table scott2.TMP_PART_DAY;
declare
lv_num pls_integer;
lv_day_cnt pls_integer;
begin
lv_num:=0;
lv_day_cnt:=1000000;
for c_f in (
select to_date('2018-11-01','yyyy-mm-dd') as dat from dual union all
select to_date('2018-12-01','yyyy-mm-dd') as dat from dual union all
select to_date('2019-01-01','yyyy-mm-dd') as dat from dual union all
select to_date('2019-01-10','yyyy-mm-dd') as dat from dual union all
select to_date('2019-02-01','yyyy-mm-dd') as dat from dual union all
select to_date('2019-04-01','yyyy-mm-dd') as dat from dual
)
loop
select nvl(max(id),0)
into lv_num
from scott2.TMP_PART_DAY
;
insert into scott2.TMP_PART_DAY
select lv_num+level as le,
sys_guid(),
sys_guid(),
c_f.dat
from dual
connect by level <=lv_day_cnt
;
commit;
end loop;
end;
/
new table
-- drop table scott2.TMP_PART_DAY1 purge;
create table scott2.TMP_PART_DAY1
(
id number(20) not null,
name varchar2(1000),
memo varchar2(1000),
create_time date
)
partition by range (create_time) interval (numtodsinterval(1, 'day'))
(partition values less than(to_date('2019-01-01', 'yyyy-mm-dd')));
online redefinition
表都有主键,这是设计表的基本要素。
-- Constants for the options_flag parameter of start_redef_table
-- cons_use_pk CONSTANT PLS_INTEGER := 1;
-- cons_use_rowid CONSTANT PLS_INTEGER := 2;
如果确实没有主键的,可以使用 rowid 试试。
数据量大的话,可以开并行
alter session force parallel dml parallel 16;
alter session force parallel query parallel 16;
step 1 验证
begin
dbms_redefinition.can_redef_table('SCOTT2','TMP_PART_DAY',1);
end;
/
step 2 开始
begin
dbms_redefinition.start_redef_table('SCOTT2','TMP_PART_DAY','TMP_PART_DAY1',null,1);
end;
/
step 3 复制依赖
declare
lv_num_errors pls_integer;
begin
dbms_redefinition.copy_table_dependents(
uname =>'SCOTT2',
orig_table =>'TMP_PART_DAY',
int_table =>'TMP_PART_DAY1',
copy_indexes =>dbms_redefinition.cons_orig_params,
copy_triggers =>true,
copy_constraints =>true,
copy_privileges =>true,
ignore_errors =>true,
num_errors =>lv_num_errors,
copy_statistics =>false,
copy_mvlog =>false
);
dbms_output.put_line('lv_num_errors='||lv_num_errors);
end;
/
查看错误
select object_name,base_table_name,ddl_txt from dba_redefinition_errors;
step 4 同步有变化的数据
begin
dbms_redefinition.sync_interim_table('SCOTT2','TMP_PART_DAY','TMP_PART_DAY1');
end;
/
step 5 结束
begin
dbms_redefinition.finish_redef_table('SCOTT2','TMP_PART_DAY','TMP_PART_DAY1');
end;
/
select dtp.table_owner,
dtp.table_name,
dtp.partition_name,
dtp.partition_position
--*
from dba_tab_partitions dtp
where 1=1
and dtp.table_name in (
'TMP_PART_DAY',
'TMP_PART_DAY1'
)
;
如果中间过程有异常时,可以放弃。
begin
dbms_redefinition.abort_redef_table('SCOTT2','TMP_PART_DAY','TMP_PART_DAY1');
end;
/