本文档用于介绍影响Oracle到MYSQL数据库和应用程序迁移的具体细节及其影响。成本和风险因素都被详细介绍,同时也会着重介绍ZTO2M和其相关技术以便了解如何完成一次高效的转换。
在过去几年中MySQL被证明是十分稳定和可收缩的数据库产品,在很多数据库排行榜上MySQL紧跟Oracle之后,是世界上最流行的开源数据库。很多企业利用MySQL社区版的免费优势,有效降低了软件许可证、硬件、管理等多方面的成本。然后从Oracle迁移到MySQL平台最大的挑战在于要将复杂的业务逻辑和数据结构转换成MySQL的格式,特别是在现有应用程序本身大量使用oracle特性例如 PL/SQL存储过程、触发器、程序包package和Oracle特有SQL语句的情况下。
由此oracle到mySQL的迁移会变得困难重重,耗费大量时间、以及异常昂贵。ZTO2M的设计就是为了简化这种迁移的复杂度,做到对于简单的应用程序使用的Oracle数据库(极少使用PL/SQL存储过程、函数、触发器或包的实例)可以一路next迁移。对于复杂度较高的场景则可以极大降低迁移工程师的工作量。这一系列技术革新的目的就是为了降低Oracle到MySQL迁移的成本和风险。在ZTO2M的帮助下,迁移的工作量可以被评估,迁移计划可以有限规划,迁移动作可以自动化运作。 在合理使用ZTO2m的前提下迁移工程师会从一个无地下脚的场景中解放出来,有效降低70%以上的工作量。
迁移复杂在哪里?
Oracle数据库提供非常先进和丰富的技术给我们的应用程序开发者来开发异常复杂的应用程序逻辑,这几乎导致开发者生成一种对Oracle的强烈依赖感。举个例子来说在开发应用程序上Oracle就像自动档位车,有效降低了开发者本身的技术门槛,让初级的开发者也能实现复杂的业务逻辑的同时保证一定的性能。其所提供的开发技术包括PL/SQL存储过程,函数,程序和触发器。
Oracle Pl/SQL语言是一种易于使用的开发语言,PL/SQL天生是对SQL的一种强大的基于过程的扩展,在各个行业PL/SQL都有广泛的使用,例如EPR行业中ORACLE EBS应用程序中大量采用PL/SQL来实现各种业务逻辑。在绝大多数应用程序中,使用PL/SQL必然导致不小数量的存储过程、包和触发器。MySQL中虽然也有类似的功能,但和PL/SQL差异巨大。
除了Oracle特有的语法外,PLSQL提供很多非ANSI标准化的复杂特性,包括如下这些:
Package包,共享包变量,内建包
%TYPE,%ROWTYPE,exception
面向对象的特性:object type,函数,集合
商业智能和XML特性
如果你需要转换PLSQL代码(过程,包,函数和触发器)或查看/查询包含Oracle 特有的SQL语法,则你不得不了解这些特性到底是如何使用的,并确定这些使用存在的分布和数量。下面是一些例子需要被重视的:
非ANSI兼容性的SQL函数,操作符和语句
results set
游标循环
exceptions
临时表
对象类型和函数
动态SQL
内建包
OLAP函数
XML函数
在你完成上述评估后;最好在理清下MySQL中对象的功能或解决方案以便替代Oracle特性的特性。一般可以在后续章节找到典型的迁移方案。
应用程序评估
除了schema和服务器端的商业逻辑转换外,用户有时还需要修改应用程序内的SQL语句。此时评估工作量将是至关重要的。
从一开始你就要检查所有哪些你的应用程序正在使用的数据库API; 获取你的应用程序源代码,这些代码包括在数据库外运行的JAVA或其他语言程序,包含在程序中的SQL语句,和存放在Oracle中的PLSQL代码;获取所有这些程序的代码并一一评估,毫无遗漏在迁移中是至关重要的。
大多数应用程序使用一种标准的API: ODBC,JDBC或ADO.NET来访问Oracle,但是一些应用程序可能使用一种原生的 API例如ORACLE OCI或Pro*C或C++。收集这些信息细节是必要的。
即便你使用的是标准API,例如 ODBC/JDBC这些驱动器,还是要对现存的SQL语句做大量的修改。举例来说 DECODE函数或左外连接语法(*)都需要被改写。ZTO2M工具可以有效抓出这些Oracle原生语句。
若应用程序确实使用了Oracle原生API例如OCI,则几乎需要全盘重写数据库访问部分的代码,修改为使用MySQL API或ODBC。
评估工具
ZTO2M工具工具可以有效评估现有Oracle数据库内使用过的SQL语句,已经创建的PLSQL对象。以下是一个简要的评估表:
基于上述评估结果,用户可以编写迁移计划。若用户只有几十个存储过程,则可以考虑做手动代码转换。但是如果你有成千上百个存储过程需要迁移,则最好还是评估使用ZTO2M的自动转换功能。
成本和风险
迁移项目相关的成本和风险主要来源于迁移的代码量。oracle独有的特性用的越多则迁移复杂性越高。同时oracle特性用的越多则自动化迁移工作所能做的也越多。
数据和DDL迁移成本
数据和DDL对象迁移是最典型的迁移对象,所以其迁移成本较低,工作量相比起代码-应用程序迁移而言简单得多。
典型的数据和DDL迁移包含如下的转换:
数据类型
约束 主外键,唯一键,空值,默认值
数据转移
虽然oracle和mysql之间的DDL语句中存在语法差异,但有着类似的数据类型(字符,数字,日期,时间,LOB大对象等)并允许你指定类似的完整性约束。
样例DDL/数据迁移评估:
由于是自动化操作,所以迁移DDL和数据的成本与表的数量和数据的大小没有直接的关系。举例来说,若数据结构差异不大,则迁移100个表和300个表在成本上是近似的。
但当表的数量和数据容量大到某个数量级别,则用户需要花费更多的时间来配置MYSQL数据库,调优数据传输速度,并关心例如索引创建性能等细节。
迁移DDL和数据的风险
典型的DDL/数据迁移的迁移风险较低。使用ZTO2M可以将整个数据库的应用DDL和数据都迁移过到MySQL数据库中。
典型的工作流如下:
启动全库传输
检查传输错误,比较表结构,比较Oracle和MySQL中的表的行数
针对所有表或有针对性的表做验证和测试数据,可以用如sqldeveloper、 mysql query browser等工具做验证。
运行应用程序连接到新的MySQL数据库做验证
数据迁移中的挑战:
虽然常规来说数据和ddl迁移是相对简单的,与之相比商业逻辑转换要复杂得多。但下面这些场景会增加数据和ddl迁移的难度:
超大数据量
若你需要迁移超大容量的数据,你可能需要进一步配置Mysql目标服务器。
极大容量的数据将直接影响迁移过程,特别是何时才能完成迁移。为了降低迁移时间,你可能需要将迁移工作以并发的形式来提高效率。当然这将增加迁移的复杂度。
对于海量数据的迁移可能在迁移过程中出现报错,若出现报错则可能导致你没有足够的时间再重新跑一次整个迁移过程。
迁移项目将受益于批量插入特性,通过bulk insert可以大批量插入数据从而减少交互和循环次数。
最小停机时间
在一些关键任务环境中,你必须让停机时间最短,例如对于医院和银行、电信等关键业务而言只允许停机1个小时。为了迎合这样的要求,就必要将数据迁移工作以最快速度并行实现,或在非停机窗口时间将静态表优先传输完成。有些时候也要利用一些同步复制工具例如goldengate来减少停机时间。
强性能要求
在一些环境中对于产品数据库性能有着极高的要求。但当迁移到MySQL后,很难保证性能要比原来的Oracle好。这样就要求用户花费更多的时间去做数据库调优,更重要的是在迁移前做必要的全盘性能测试。
数据迁移风险
具有挑战性的数据迁移工作不是简单的点击下鼠标就能完成的。在正式迁移前建议做一个完整的 POC proof of concept。
在大多数情况下,对于迁移进程而言简意做如下的准备:
做 迁移POC以检查可行性
测试迁移以便做完整的测试,包括 可用性和性能
产品迁移
商业逻辑转换成本
若数据库包含几十个存储过程和触发器,则很容易纯手工重写代码到 MySQL的标准。若你有成千个存储过程和触发器,则手动转换的成本太高了。用户必须考虑基于自动化工具来实现大量代码的转换。
手动转换的成本直接与代码的函数相关。换句话说,自动化工具极大的降低了成本,并让迁移上百万行代码的项目存在一个合理的报价。
取决于要转换的代码行数,自动化转换商业逻辑代码对比手动转换降低了7~10倍的成本。
oracle特性在代码中使用的分布和频率决定了商业逻辑转换的复杂度和自动化工具工作的复杂度级别。
ZTO2M的有效自动转换可以针对95%以上的复杂业务逻辑做到自动转换。
下面是一个简单的例子,对于业务逻辑转换而言的工作项目罗列:
若你要比较DDL/数据和业务逻辑的迁移,则你回发现后者的成本占总本的约95%。这是Oracle到MySQL迁移的基本因子。
业务逻辑迁移风险
若有大量的代码行以及分布广泛的oracle特有特性要做迁移,则转换存在较大的风险,这样需要几个步骤来实现迁移。
负责做迁移项目的员工应当有该项目的开发者和管理人员,并拥有较为丰富的oracle和MySQL使用经验。他们需要清楚工作中的挑战、任务和各个阶段。
完整的评估
在最初的阶段,用户需要实施一个完整的数据库评估。作为整个评估的产物用户将知道哪些特定的功能需要做转换,例如用户最终要决定使用何种方案去替换非 ANSI的 Oracle特性。
用户需要判断是否针对各个特性存在一个解决方案。一些Oracle特性是不易于去转换到MySQL的,这时则需要重新设计这些功能
在所有代码基础上做 POC
例如 ZTO2M的自动化工具让迁移易于去执行,完全可以在初始阶段直接对所有的代码做转换测试。我们建议在一开始就使用 ZTO2M介入进来,以便暴露所有的潜在问题,并厘清哪些部分是可以自动化完成的。
最重要的是,这会让你对这些笨重的PL/SQL 代码的转换充满信心。
尽可能使用自动化迁移
虽然纯手工迁移的成本很高,但其在初始阶段有就有效发掘了解决了瓶颈。与之对比,自动化工具在低成本的前提下让转换能够大量重复执行,但需要用户更多的反馈介入其中。 通常来说,手动转换是一项十分繁重的体力和脑力劳动,即便对于有经验的人而言也会出现一系列的人类人为错误。 几乎没有人能承受常见做这样的工作,因此手动转换是高成本的,同时也会耗费大量的时间。
早期测试
在早期阶段测试应当可以最小化工程的风险。用户可以在应用级别的功能测试还没开始前就开展单元测试,或实施代码核验。
利用自动化工具可以自动产生 测试场景来以特定变量调用存储过程和函数并比较结果。请注意这并不能替代应用级别的功能测试,但可以帮助发现潜在的问题。
应用程序转换
除了服务器端的业务逻辑转换外,在大多情况下你还需要修改你的应用程序以适应MYSQL。
在 java或Powerbuild应用中都可能存在非ANSI的SQL语句,不同于MySQL的 SQL语法的语句都需要修改。
例如oracle的左外连接(+)使用特殊的语法,那么转到MySQL中就要特别当心了。decode,nvl和sysdate都要特别注意。
你不能光使用find/replace寻找替换来替换函数名,在大多数情况下,函数都可能有不同的参数语法或需要SQL语句做整体修改。
此外简单的string字符串替换可能会替换那些不该替换的位置,例如字符串,或java语言语句。
最佳的方式是使用例如ZTO2M工具的自动修改应用程序的能力来转换SQL语句到合理的MySQL语法。
ZTO2M工具可以正确识别代码中SQL语句,实施转换,并生成修改报告,极大地简化了转换工作。
方案规划
合理的方案规划对于成功的迁移而言至关重要,典型的迁移步骤如下:
评估涌来分析数据库和应用程序,定义迁移范围,记录那些Oracle特性功能的使用。
基于评估产生的信息,用户可以定义具体要使用的方法途径:手动转换还是自动转换以及相关的风险。
在早期阶段完成一次全部转换 这是一次POC
假设你的数据库有2000个存储过程,那么你可以使用ZTO2M来转换所有的代码,特别是在 POC阶段。我们建议你这样做无论你是否喜欢一个模块一个模块来做测试和部署。
显然现在是迁移的早期阶段,但对整个迁移项目的基本了解和反馈是很重要的,这让我们大概知道要踩哪些坑。显然用软件实现自动化转换与手工转换要花上几十个小时来预习这些代码要来的核算。
基于ZTO2M你可以实施一个整合和统一的迁移方法。 与之对比手工转换必然是在一群人中开展,不同的存储过程,不同的代码风格现在又要求一堆人来修改,可以想象工作的繁重。所以显然风格约统一结果越好。
理想状况下用户的转换完成后可以在MySQL中直接无错运行。这意味着所有的表、函数、过程和触发器都在MySQL中成功创建。
对于复杂的应用代码而言100%转换是十分困难的,我们通常还是要做一些手动修复工作。
运行时,逻辑以及性能测试
迁移经常是以一个一个模块的形式来实现的。当你已经转换了服务器端的业务逻辑,而应用程序还没做转换且应用级测试都还没做时,应当先做数据库的转换。
用户可以选择几个有代表性的或特别重要的过程来做代码检查。当然你可能在检查代码时并不能找出所有的毛病,但在早期阶段这仍是必要的。
通过检查转换后的代码,你可以找出使用了哪些替代技术方案,并评估转换质量。
若你想深入了解转换的技术背景则有必要对哪些oracle独有特性的转换情况列出清单。
即便你的代码在转换后可以在MySQL中成功创建,也不意味着运行时不会出错。许多报错可以在运行时快速发现。
ZTO2M可以针对存储调用采用不同的输入变量;在测试代码时ZTO2M可以知道哪些变量被使用了,使用的变量类型是字符串还是日期常数,流程控制条件。 为了实施复杂的逻辑和性能测试,用户也可以用真实数据配合自己开发的测试脚本来满足多种多样的测试场景。
若你针对oracle数据库使用自动化测试软件,则考虑升级这些自动化质控软件以应对MYSQL。
典型的转换场景 - 样例
虽然转换任务和方案是case by case的,也就是说每个项目的都差异很大;但转换工作中的大部分内容还是相似的。
注意 所有下面提到的转换场景都可以使用ZTO2M来自动转换。
DDL
oracle和mysql都支持create table语句,但语法差异很大:
数据类型
--- ORACLE
create table employees
( id number(5),
name varchar2(120),
hire_date date,
salary number(7),
dept_id number(2)
保留词
Oracle和MySQL 使用不同的保留词 ,所以一些列名在MySQL查询中要打上引号:
--- ORACLE
SELECT product_id,limit from product_data;
--- MYSQL
SELECT product_id,'limit' from product_data;
查询和PLSQL代码
你需要修改SQL语句以修改函数和表达式的语法。PL/SQL代码要完整地转换到MySQL SQL过程语法。
Outer Joins外连接
oracle对外连接支持特定的语法,并被很多应用程序大量使用:
--- ORACLE
SELECT e.name,d.name from employees e , departments d
where e.dept_id= d.id(+);
-- MYSQL
SELECT e.name, d.name from employees e left outer join departments d on e.dept_id =d.id;
给列自动分配ID
Oracle在12c之前不支持自增列(auto0increment identity column),一般用sequence 序列来实现对应用程序新ID的分配。
Oracle中虽然创建一个简单的序列sequence对象可以用来给多张表分配值,但绝大多数场景中也就只是给一张表分配ID罢了,所以可以利用oracle中的自增列 auto-increment column 。
代码形式如下:
--- ORACLE
create table employees
( id number(5) primary key,
name varchar2(120),
hire_date date,
dept_id number(2)
create trigger emp_id before
insert on employees
for each row
BEGIN
select emp_id_seq.nextval into :new.id from dual;
create table employees
( id int auto_increment primary key ,
name varchar2(120),
hire_date datetime,
dept_id tinyint);
不需要创建trigger
同一个event多个触发器
在Oracle中,针对同一张表用户可以定义多个触发器应对同一个事件(例如针对employees表的INSERT事件有多个触发器)。
在MySQL里这个行不通,所以要求把针对该事件的所有代码都写在一个触发器里。
包和共享变量
在Oracle中,一个包是一组相关存储过程和函数,并可以共享变量。MYSQL中存储过程和函数都要转换成单独的对象。
包变量可以在包中的存储过程中被修改,之后另一个包中国年的存储过程可以看到并传递回变更的变量。 在MYSQL中可以以@符号开头的会话变量来替代这一功能:
---ORACLE
CREATE PACKAGE BODY emp_pack
processed NUMBER DEFAULT 0;
PROCEDURE new_employee AS
BEGIN
processed := processed + 1;
PROCEDURE raise_salary AS
BEGIN
processed := processed + 1;
返回的结果集
在Oracle中要用一个游标变量(REF CURSOR)当一个外参来返回结果集。 在很多场景中,MYSQL里就是很简单的SELECT
--- ORACLE
CREATE PROCEDURE get_salaries
(d_id IN NUMBER, cur OUT
SYS_REFCURSOR)
BEGIN
OPEN cur FOR
SELECT id, name, salary
FROM employees
WHERE dept_id = d_id
ORDER BY name;
%TYPE 和 %ROWTYPE 数据类型定义
Oracle中%TYPE属性允许开发者让PL/SQL变量和表上的列的数据类型一致。在MYSQL里,用户需要精确指定数据类型。
--- ORACLE
v_emp_name employees.name%TYPE;
v_emp_rec employees%ROWTYPE;
--- MYSQL
v_emp_name VARCHAR(120)
v_ emp_id INT
v_ emp_name VARCHAR(120)
v_ emp_hire_date DATETIME
v_ emp_salary INT
v_ emp_dept_id TINYINT
JAVA应用程序中的SQL转换
在JAVA应用程序需要这样修改SQL语句语法:
---ORACLE
PreparedStatement ps = null;
ResultSet rs = null;
String sql = “SELECT e.name, d.name” +
“FROM employees e, departments d” +
“WHERE e.dept_id = d.id(+)”;
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
---MYSQL
PreparedStatement ps = null;
ResultSet rs = null;
String sql = “SELECT e.name, d.name” +
“FROM employees e LEFT OUTER JOIN” +
“departments d ON e.dept_id = d.id”;
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
powerbuilder应用程序中的SQL转换
在powerbuilder中,需要这样修改SQL语法:
---ORACLE
datawindow(units=0 processing=0
print.orientation = 0
print.preview.buttons=no)
table(column=(type=char(120)
updatewhereclause=yes name=e_name
dbname="employees.name" )
column=(type=char(120)
updatewhereclause=yes name=d_name
dbname="departments.name" )
retrieve="SELECT e.name, d.name
FROM employees e, departments d
WHERE e.dept_id = d.id(+)”)
---MYSQL
datawindow(units=0 processing=0
print.orientation = 0
print.preview.buttons=no)
table(column=(type=char(120)
updatewhereclause=yes name=e_name
dbname="employees.name" )
column=(type=char(120)
updatewhereclause=yes name=d_name
dbname="departments.name" )
retrieve=" SELECT e.name, d.name
FROM employees e LEFT OUTER JOIN
departments d ON e.dept_id = d.id”)
一些其他的不支持的功能
ORACLE PL/SQL中很多功能点仍不被MYSQL SQL过程语言支持。若这些功能确实在源库中有被使用,则需要利用一些方法绕过:
PLSQL集合
MYSQL中可以使用临时表和SQL DML 操作(SELECT ,INSERT,UPDATE,DELETE)
RAISE_APPLICATION_ERROR
在 MYSQL 存储过程中可以使用 UDF来报错
UTL_FILE内建包
在 MYSQL 存储过程中可以使用 UDF来操作文件
复杂的业务逻辑
复杂的业务逻辑可以转成JAVA代码
迁移到MYSQL的收益时巨大的,同时自动化迁移也是经济实惠的。使用ZTO2M功能来简化迁移项目可以答复降低项目周期,提升转换质量。