迁移内容分为两部分:
1. 过程和视图等脚本迁移,无迁移工具,需要手动改写。
2. 表结构和数据迁移,可以采用工具完成,详细方案步骤见下文。
为了节省迁移工作量,调研了市场上目前免费的常用数据迁移工具:
1. MySQL Workbench
缺点:支持各种数据库迁移到MySQL,唯独不支持Oracle迁移MySQL
2. Navicat Premium
缺点:表结构迁移时,Date字段类型转换不正确,并且不支持类型映射关系修改
报错:[Err] [Dtf] 1426 - Too-big precision 7 specified for 'HIREDATE'. Maximum is 6.
3. Convert Oracle to MySQL
缺点:软件功能简单,迁移时出现问题,没有正确的提示。
4. MySQL Migration Toolkit(推荐)
优点:mysql官方提供的数据库移植工具,可以将任何数据源转换成mysql的数据。
软件功能稳定可靠,使用简单,支持Oracle11g和之前版本往MySQL5.0以上版本迁移。
缺点:
1. 软件最后发布版本是2006.03.11,不支持Oracle 12c迁移,需要做下中转,12c数据导出到11g,然后在11g基础上迁移。
1. 数据类型映射
Oracle |
MySQL |
char |
char |
varchar2 |
varchar |
number(x,x) |
decimal(x,x) |
date |
datetime |
clob |
longtext |
2. 函数映射
Oracle |
MySQL |
substr |
substring |
nvl |
ifnull |
round |
round |
lpad |
lpad |
trunc |
truncate |
floor |
floor |
ceil |
ceil |
trim |
trim |
upper |
upper |
lower |
lower |
从源Oracle库导出dmp文件,将该dmp文件导入Oracle 11g,使用MySQL Migration Toolkit迁移到本地MySQL,再将该MySQL库备份恢复到服务器。
12c高版本dmp文件导入到11g低版本数据库,提示版本兼容错误,所以导出时必须加上低版本号version=11.2.0.1.0
样例:
expdp scm/123456 directory=exp_dir dumpfile=scm_1101.dmp schemas=scm logfile=scm_1101.log version=11.2.0.1.0
因为dmp文件已经兼容11g了,所以可以直接导入。
样例:
impdp scm/123456 directory=exp_dir dumpfile=scm_1101.dmp remap_schema=scm:scm remap_tablespace=scm:scm,scm_idx:scm_idx content=all
1. 软件设置
工具有个bug,会去注册表里找版本为1.5的JRE。但是如果机器装的是1.6或1.7或更高版本,注册表里是不会有1.5版本的JRE的任何痕迹。需要在注册表内添加jre路径:
\HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment,新增“项1.5”,然后新增字符串值“RuntimeLib”,数值数据D:\ProgramFiles\Java\jre7\bin\server\jvm.dll
①. Migration of type Oracle Schema,选择Multilanguage,指定schema的字符集为UTF8,和Oracle字符集保持一致。
②. Migration of type Oracle Table,选择Data consistency/multilanguage,会将表导入到InnoDB引擎,并且使用UTF8字符集,和Oracle保持一致。
③. 三张表(t_invt_batch_item, t_invt_item, t_pay_pre_in)定义的字段含有默认值“DEFAULT sys_guid()”,这三张表需要在“Schema Creation”环节去除默认值设定并手动创建,否则数据丢失。
备份数据库
mysqldump -u root -p scm > d:\scm.sql
恢复数据库
Source d:\scm.sql
效率还可以,备份测试环境26.4M的数据,用时5秒,恢复用时20秒。
1. 表定义Primary key约束,迁移后丢失,只是生成一个unique index
解决方法:
两部分处理:
1. Oracle中主键数据不来自于sequence,考虑到整体数据库性能,需要在MySQL每张表内增加一个自增字段为主键。
原来主键作为unique key,也就是unique index。
根据Oracle数据字典生成创建脚本:
select 'ALTER TABLE '||t.table_name||' ADD kid INT AUTO_INCREMENT PRIMARY KEY;' from user_tables t where ...;
2. Oracle主键来自于sequence
将主键约束加上,和Oracle保持一致。
根据Oracle数据字典生成创建脚本:
SELECT 'ALTER TABLE '||t.table_name||' ADD CONSTRAINT '||constraint_name||' PRIMARY KEY ('||
(SELECT LISTAGG(cc.column_name, ',') WITHIN GROUP (ORDER BY cc.position ASC)
FROM user_cons_columns cc
WHERE cc.owner = t.owner
AND cc.constraint_name = t.constraint_name)||');'
FROM user_constraints t
WHERE t.constraint_type = 'P';
2. Oracle sequence在MySQL如何代替?
解决方法:
①. 单纯自增的字段,MySQL使用auto_increment来定义
②. 字符加自增联合的字段,比如bill_id,使用前缀+自增数字拼接而成,在MySQL侧自定义函数nextval生成自增数字来模拟oracle sequence,这里重点优化并发性的问题。
3. Oracle sys_guid()函数生成唯一随机数,对应的存储字段迁移到MySQL如何替换?
解决方法:
使用uuid()获取全库唯一标示。
4. 前端代码修改
分页代码
分页代码使用LIMIT代替ROWNUM
Oracle代码样例:
select *
from (select t.*, rownum AS ROWNO
from (select * from t_order order by creat_date desc) t
where rownum <= 1 * 10) a
where a.ROWNO > (1 - 1) * 10;
需要修改为MySQL写法:
select * from t_order order by creat_date DESC LIMIT 0, 10;
0为下标,10为记录条数,这两个值根据每页显示记录数和要显示页码计算出来。
LIMIT下标从0开始。
获取结果集修改
Oracle侧返回游标。在MySQL中不支持返回游标,直接返回结果集,需要前端重新获取结果集获取方式。
SQL语句中函数修改
Oracle |
MySQL |
nvl(comm, 0) |
ifnull(comm, 0) |
substr('abcdefg', 2, 3) |
substring('abcdefg', 2, 3) |
decode(dealer.company_name,NULL,t1.company_name,dealer.company_name) |
case when dealer.company_name is null then t1.company_name else dealer.company_name end |
to_date('20161120', 'yyyymmdd') |
str_to_date('20161121133752', '%Y%m%d%H%i%s') |
to_char(sysdate, 'yyyymmddhh24miss') |
date_format(now(), '%Y%m%d%H%i%s') |
日期计算
Oracle中增加一天 date + 1;减少一天 date - 1;
在MySQL中日期变化
增加一天date_add(now(), interval 1 day)
减少一天date_sub(now(), interval 1 day)