-- 创建测试数据
-- 创建一张临时表
create table tbl_yy as
select rownum as id,
to_char(sysdate + rownum/24/3600, 'yyyy-mm-dd hh24:mi:ss') as inc_datetime,
trunc(dbms_random.value(0, 10000)) as random_id,
dbms_random.string('x', 20) random_string
from dual
connect by level <= 10000;
commit;
-- 如果觉得数据不够,可以再继续插入数据测试
insert into tbl_yy
(ID, INC_DATETIME,RANDOM_ID,RANDOM_STRING)
select rownum as id,
to_char(sysdate + rownum / 24 / 3600, 'yyyy-mm-dd hh24:mi:ss') as inc_datetime,
trunc(dbms_random.value(0, 100)) as random_id,
dbms_random.string('x', 20) random_string
from dual
connect by level <= 100000;
commit;
-- 创建临时表
-- 临时表会占用主表同样的大小,要检查好表空间容量。
create table int_tbl_yy as select * from tb_yy where rownum = 0;
-- 修改字段类型,number改成varchar2
alter table int_tbl_yy modify RANDOM_ID varchar2(22);
-- 全局配置,变量替换,如下直接复制到sqlplus或工具执行。
-- 临时表会占用主表同样的大小,要检查好表空间容量。
-- 生产环境不要在业务高峰期做操作
-- 用户名
define USERNAME = 'yy';
-- 原表名
define SOURCE_TAB = 'tbl_yy';
-- 临时表名,需要手工提前创建
define INT_TAB = 'int_tbl_yy';
-- 映射表的字段名
-- 由于define最大长度只支持240个字符,映射要在第4点自己配置col_mapping这个参数,如下是生成的方法,注意手工去掉最后一个逗号,
-- 注意类型转换,如id(varchar2 要转成id(number) ,映射的时候需要保证字段类型一致,使用to_number解决,如:to_number(id) id,
-- select listagg(column_name || ' ' || column_name || ',' ) col_name from user_tab_columns where table_name='&SOURCE_TAB';
-- 并行度
define PARALLELS = 4;
-----------分割线-执行步骤---------------------
-- 1.打开并行
alter session force parallel dml parallel &PARALLELS;
alter session force parallel query parallel &PARALLELS;
-- 2.重定义为分区,使用rowid,建议为临时表开启行迁移
alter table &INT_TAB enable row movement;
-- 3.检查dbms_redefinition是否在这个表上工作
--基于主键
-- exec DBMS_REDEFINITION.CAN_REDEF_TABLE('custinfo','fm',DBMS_REDEFINITION.CONS_USE_PK);
--基于rowid
begin
dbms_redefinition.can_redef_table(uname => '&USERNAME',
tname => '&SOURCE_TAB',
options_flag => DBMS_REDEFINITION.CONS_USE_ROWID);
end;
/
-- 4.调用DBMS_REDEFINITION.START_REDEF_TABLE存储过程启动重定义进程
-- 接下来开始重新定义
-- BEGIN
-- DBMS_REDEFINITION.START_REDEF_TABLE(UNAME =>'custinfo', ORIG_TABLE=>'fm',INT_TABLE=>'int_fm',OPTIONS_FLAG=>dbms_redefinition.cons_use_pk);
-- END;
-- 基于rowid
-- number , varchar2 互转要用to_char 或to_number 做映射。
-- select listagg(column_name || ' ' || column_name || ',' ) from dba_tab_columns where table_name=upper('&SOURCE_TAB');
set timing on;
begin
DBMS_REDEFINITION.START_REDEF_TABLE(uname => '&USERNAME',
orig_table => '&SOURCE_TAB',
int_table => '&INT_TAB',
col_mapping => 'ID ID,INC_DATETIME INC_DATETIME,to_char(RANDOM_ID) RANDOM_ID,RANDOM_STRING RANDOM_STRING',
options_flag => DBMS_REDEFINITION.CONS_USE_ROWID);
end;
/
-- 5.复制依赖对象。(自动创建任何触发器、索引、物化视图日志、授予和对 custinfo.int_fm 的约束)。
-- copy_indexes => 0 索引报错可以设置为0
DECLARE
num_errors PLS_INTEGER;
BEGIN
DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(uname => '&USERNAME',
orig_table => '&SOURCE_TAB',
int_table => '&INT_TAB',
copy_indexes => DBMS_REDEFINITION.cons_orig_params,
copy_triggers => TRUE,
copy_constraints => TRUE,
copy_privileges => TRUE,
ignore_errors => FALSE,
num_errors => num_errors,
copy_statistics => TRUE);
END;
/
-- 6.利用sync_interim_table过程同步临时表的数据减少finish_redef_table的耗时:
begin
dbms_redefinition.sync_interim_table(uname => '&USERNAME',
orig_table => '&SOURCE_TAB',
int_table => '&INT_TAB');
end;
/
-----------分割线-后面二步是结束操作,执行后会做最后阶段的切换------------
-- 7.执行finish_redef_table过程完成重定义:
begin
dbms_redefinition.finish_redef_table(uname => '&USERNAME',
orig_table => '&SOURCE_TAB',
int_table => '&INT_TAB');
end;
/
-- 关掉并行
-- 以上成功完成了对SALES表的Online Redefinition,由非分区表在线重定义为分区表且增加了一个字段。
-- 这里因为我们使用rowid方式,所以重定义完的表上会多出一个隐藏字段, 从10.2开始M_ROW$$的隐藏列会被命名为SYS_%DATE%的形式,且默认即为unused状态:
alter session force parallel dml parallel 1;
alter session force parallel query parallel 1;
alter table &SOURCE_TAB drop unused columns;
select * from dba_unused_col_tabs ;
-- 删除临时表
alter table &INT_TAB nologging;
drop table &INT_TAB;
-------------------------分割线-结束--------------------------------
-- 异常处理
-- 如果失败了可以取消
-- begin
-- dbms_redefinition.abort_redef_table(
-- uname => '&USERNAME',
-- orig_table => '&SOURCE_TAB',
-- int_table => '&INT_TAB');
-- end;
-- /