一、概述
最近做的一个项目,在很大的程度上面是在做数据迁移。数据迁移往往是项目最大的风险点。在一些大的重构项目中,往往会有一个团队专门负责,可见其重要性。在项目发布中,数据迁移往往会占用很多的时间。数据迁移需要考虑很多的情况,如:迁移方案、数据备份、迁移总时间、迁移时间点、迁移后check。
二、一个例子
项目是想把一个登陆id:member_id换成后台交互的ali_id。为此有一个map表:cbu_member_id_mapping。我们统计了数据量大约在1亿左右。
- 为了实现无缝迁移,我们打算先在每个表上面添加一列,命名为:TMP_ALIID
- 为了效率,我们打算实现并发执行。实现方式为通过把 主键mod n来实现。
- 为了统一脚本,我们打算用动态sql来实现。
- 为了看任务执行的进度,我们设计了一个任务表。
- 为了记录异常情况,我们记录了异常表
脚本如下:
1、筛选条件表
create table fin_filtrate_tbd(
tableName varchar(64), --需订正的表名
domain varchar(64),
sql varchar2(2048)
);
--添加筛选条件
truncate table fin_filtrate_tbd;
insert into fin_filtrate_tbd values('fin_contract','nirvana','select p.id,p.ali_member_id_old from fin_contract p where (product_id like ''CTP%'' or product_id = ''EW\EWC'' or product_id like ''ITBU%'' or product_id like ''OTH%'') and p.ali_member_id is null and ali_member_id_old is not null');
insert into fin_filtrate_tbd values('fin_contract','zeus','select p.id,p.ali_member_id_old from fin_contract p where not (product_id like ''CTP%'' or product_id = ''EW\EWC'' or product_id like ''ITBU%'' or product_id like ''OTH%'') and p.ali_member_id is null and ali_member_id_old is not null');
2、创建错误日志表
/**
select * from fin_unifyid_progress_tbd order by now desc; 查看执行过程
select * from fin_unifyid_errolog_tbd;查看报错日志
**/
create table fin_unifyid_errolog_tbd(
tableId varchar(64 ), --需要订正记录ID
tableName varchar(64 ), --需订正的表名
errcode number,
errmsg varchar2(1024 )
);
--记录任务结果
create table fin_unifyid_progress_tbd(
now date,
eigenvalue varchar(64),
num number
);
3、存储过程
create or replace procedure upgradeMemberId(tableNametemp in varchar2, --更新表名
domaintemp in varchar2 --中供诚信通代号
--batchtemp in number --批次
) as
v_sql varchar2(256);
v_errcode varchar2(64);
v_errmsg varchar2(256);
v_cursor_sql varchar2(512);
v_id number;
v_member_id varchar2(256);
v_ali_id number;
TYPE type_cursor is ref cursor;
v_cursor type_cursor;
v_amount number := 0; -- batch commit number
-- v_partition number := 3; --v_partition分区数
begin
begin
select a.sql
into v_cursor_sql
from fin_filtrate_tbd a
where a.tableName = tableNametemp
and a.domain = domaintemp;
OPEN v_cursor FOR v_cursor_sql;
-- using v_partition, batchtemp;
LOOP
fetch v_cursor
into v_id, v_member_id;
exit when v_cursor%notfound;
if (domaintemp = 'nirvana') then
v_sql := ' select NVL(sum(b.ali_id),0) from cbu_member_id_mapping b where b.member_id=:1 AND ROWNUM = 1';
execute immediate v_sql
into v_ali_id
using v_member_id;
if v_ali_id != 0 then
v_sql := 'update ' || tableNametemp || ' set ' ||
' TMP_ALIID=:1,ALI_ID=:2 where id=:3';
execute immediate v_sql
using to_char(v_ali_id), v_ali_id, v_id;
end if;
else
v_sql := 'update ' || tableNametemp || ' set ' ||
' TMP_ALIID=:1 where id=:2';
execute immediate v_sql
using v_member_id, v_id;
end if;
v_amount := v_amount + 1;
if (mod(v_amount, 1000) = 0) then
insert into fin_unifyid_progress_tbd
values
(sysdate,
tableNametemp || '_' || domaintemp || '_' || 3,
v_amount);
commit;
end if;
end LOOP;
exception
when others then
v_errcode := sqlcode;
v_errmsg := sqlerrm;
insert into fin_unifyid_errolog_tbd
values
(v_id, tableNametemp, v_errcode, v_errmsg);
END;
commit;
close v_cursor;
commit;
end upgradeMemberId;