-- start
-- 错误日志表-临时
create table ins.err_log_20190826(status varchar2(200));
-- 增加可空列
alter table ins.target_table add target_column NUMBER(2);
-- 给可空列增加默认值
-- 注意:这一操作是为了防止新数据生成,新字段值为null,这样游标执行无法彻底更新完所有null值,导致最后执行出错
alter table ins.target_table modify target_column default 0;
-- 拆分若干个小事务更新:其中5000这个值源于实际测试得出,每5000提交一次事务,效率较高,实际中,各自可以自行测试
declare
v_cnt pls_integer;
begin
v_cnt:=1;
while v_cnt>0 loop
update ins.target_table t set t.target_column = 0 where t.target_column is null and rownum<=5000;
v_cnt:=sql%rowcount;
commit;
end loop;
end;
-- 修改列非空
alter table ins.target_table modify target_column not null;
其中上述游标语句也可以写出如下:
declare
n1 number :=0;
v_str varchar2(200);
begin
for i in (select target_id from ins.target_table)
loop
n1 := n1+1;
update ins.target_table set target_column = 0 where target_id = i.target_id;
if mod(n1,5000)=0 then
commit;
end if;
end loop;
commit;
exception
when others then
rollback;
v_str := 'target_table' || SQLCODE || '_' || SQLERRM;
insert into err_log_20190826 (status) values(v_str);
commit;
end;
grant create any table to 用户;
grant alter any table to 用户;
grant drop any table to 用户;
grant lock any table to 用户;
grant select any table to 用户;
grant create any trigger to 用户;
grant create any index to 用户;
-- 通过ROWID是否可以重定义
begin
DBMS_REDEFINITION.can_redef_table('INS','test_table', dbms_redefinition.cons_use_rowid);
end;
建立中间表
CREATE TABLE INS.test_table_temp
(
id NUMBER(10) NOT NULL,
link_id NUMBER(10) NOT NULL,
link_TYPE NUMBER(2) NOT NULL,
flag NUMBER(1) DEFAULT 0 NOT NULL,
CREATE_ID NUMBER(10),
CREATE_TIME TIMESTAMP(6) DEFAULT sysdate,
MODIFY_ID NUMBER(10) ,
MODIFY_TIME TIMESTAMP(6) DEFAULT sysdate
);
开始重定义
-- 重定义
begin
DBMS_REDEFINITION.START_REDEF_TABLE('INS','test_table','test_table_temp',null,dbms_redefinition.cons_use_pk);
end;
---------需要注意这里的输入参数选择
PROCEDUREstart_redef_table(uname IN VARCHAR2,----用户名
orig_table INVARCHAR2,----源表名
int_table INVARCHAR2,----中间表名
col_mapping IN VARCHAR2 :=NULL,---源表和中间表列之间的映射,map;
options_flag IN BINARY_INTEGER := 1,---重定义方式,这里的 1 代表主键模式 2 代表ROWID模式 (可以直接使用oracle提供的常量)
orderby_cols IN VARCHAR2 := NULL,---对于分区表重定义的时候,分区列名
part_name INVARCHAR2 :=NULL);---对于分区表重定义的时候,需要重定义的分区。其中最后2个参数没用到,因为这里是由普通表转换为分区表;
给中间表建立索引等约束
-- 由于索引名称是全局的,所以这里的命名肯定不能与原表冲突,如果必须要改为原表表名的可以在结束重定义后,删除中间表,再次修改索引名称
create index INS.IDX_test_table_temp_1 on ins.test_table_temp (link_id);
create index INS.IDX_test_table_temp_2 on ins.test_table_temp (link_TYPE);
锁定同步数据(可选)
-- 多次同步数据,可以减少结束重定义时的等待时间
begin
DBMS_REDEFINITION.sync_interim_table('INS','test_table','test_table_temp');
end;
结束重定义
-- 结束重定义
begin
DBMS_REDEFINITION.FINISH_REDEF_TABLE('INS','test_table','test_table_temp');
end;
删除中间表
-- 此时原表的结构已经是我们想要的结构,中间表是原表的初始结构
drop table ins.test_table_temp