oracle 在线重定义 dbms_redefinition

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;
/

发布了710 篇原创文章 · 获赞 70 · 访问量 49万+

猜你喜欢

转载自blog.csdn.net/ctypyb2002/article/details/103175838