236  
查询码:00000663
Oracle To MySQL数据迁移方案
作者: 李晶晶 于 2020年08月07日 发布在分类 / 人防组 / 人防后端 下,并于 2020年08月07日 编辑
Oracle Mysql 迁移

1          概述

迁移内容分为两部分:

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基础上迁移。

2          方案详细内容

2.1         迁移映射

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

2.2         具体方案

从源Oracle库导出dmp文件,将该dmp文件导入Oracle 11g,使用MySQL Migration Toolkit迁移到本地MySQL,再将该MySQL库备份恢复到服务器。


2.2.1          导出dmp文件

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


2.2.2          导入dmp文件

因为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

2.2.3          MySQL Migration Toolkit转换数据

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


2. 迁移注意点

. 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”环节去除默认值设定并手动创建,否则数据丢失。


2.2.4          MySQL备份并恢复到服务器

备份数据库

mysqldump -u root -p scm > d:\scm.sql

恢复数据库

Source d:\scm.sql

效率还可以,备份测试环境26.4M的数据,用时5秒,恢复用时20秒。

2.3         迁移存在的问题和风险

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)



 推荐知识

 历史版本

修改日期 修改人 备注
2020-08-07 17:05:18[当前版本] 李晶晶 1.0

  目录
    知识分享平台 -V 4.8.7 -wcp