**吴海存,**10g / 11g / 12c OCM,Oracle Exadata / Golden Gate专家,曾于Amazon和Oracle公司担任全球业务资深DBA,目前供职于中国农业银行,负责数据库前沿技术研究和支持。
导读
随着MySQL 8.0的发布,MySQL的功能和性能有了较大的增强,越来越多的企业都选择了使用成本低且部署方案灵活的MySQL数据库。那么,将数据从当前数据库迁移到MySQL时,从应用层、数据库层都需要注意哪些方面?为了顺利完成复杂的迁移工作又需要考虑和解决哪些方面的问题?
本文以Oracle迁移到MySQL为例,重点阐述Oracle和MySQL数据类型差异、业务实现差异、迁移方式以及迁移过程中的一些风险点,供大家参考,文中如有疏漏之处,望在评论区指正。
在异构数据库迁移过程中,我们从如下几个方面进行思考:
1、迁移类型
Oracle迁移到MySQL主要涉及数据结构迁移、数据迁移、业务迁移这三类,我们需要考虑如下几个难点:
- 数据类型差异导致数据结构迁移过程中需要进行改造和处理;
- 数据迁移中 Oracle LOB字段、null值和’’值以及迁移方式为迁移难点。
- 业务迁移中由于MySQL不支持并行、不支持物化视图,会涉及到存储过程改造,同义词改造,DBlink、sequence、分区表以及复杂sql语句的改造。
2、迁移流程
我们需要整理一个完整的迁移流程:1、确定迁移范围;2、迁移评估;3、选择迁移方式;4、迁移验证,以此来确保迁移工作的进展和顺利完成。
1)确定迁移范围
从Oracle迁移到MySQL是一项昂贵且耗时的任务,重要的是要了解要迁移的范围,不要浪费时间来迁移不再需要的对象。另外,检查是否需要迁移所有的历史数据,不要浪费时间来复制不需要的数据,例如过去维护中的备份数据和临时表。
2)迁移评估
经过初步检查后,迁移的第一步是分析应用程序和数据库对象,找出两个数据库之间不兼容的特性,并估算迁移所需的时间和成本。例如由于Oracle与MySQL之间数据结构存在差异,且MySQL不支持并行、不支持物化视图、8.0以上才支持函数索引,可能涉及到存储过程改造,同义词改造,DBlink、sequence、分区表以及复杂sql语句的改造等工作。
3)迁移方式
通过对迁移所需时间和成本选择不同的迁移方法或者工具进行迁移,可以分为实时复制(例如利用GoldenGate实时同步数据使业务影响时间最小),或者一次性加载(例如采用 Oracle将数据表导出到csv文件后,通过load或者mysqlsh工具导入到MySQL中)。
4)验证测试
测试整个应用程序和迁移的数据库非常重要,因为两个数据库中的某些功能相同,但是实现方式和机制却是不同的。我们需要做充分的验证测试:
- 检查是否正确转换了所有对象;
- 检查所有DML是否正常工作;
- 在两个数据库中加载样本数据并检查结果,比如来自两个数据库的SQL结果应该相同;
- 检查DML及查询SQL的性能,并在必要时进行SQL改造。
首先,我们先从术语、元数据、表对象、索引类型、分区等方面了解一下Oracle和MySQL的差异和区别。
一、MySQL和Oracle差异
1.1 MySQL和Oracle术语差异
1.2 MySQL和Oracle配置用户差异
1.3 MySQL和Oracle对表的限制差异
1.4 MySQL和Oracle虚拟列和计算列差异
Oracle和MySQL的虚拟列(在MySQL中也称为生成的列)基于其他列的计算结果。它们显示为常规列,但它们的值是计算所得,因此它们的值不会存储在数据库中。虚拟列可与限制条件、索引、表分区和外键一起使用,但无法通过 DML 操作操纵。
与Oracle的虚拟列相反MySQL生成的列必须指定计算列的数据类型。必须指定GENERATED ALWAYS值,如以下示例中所示:
Oracle虚拟列:
SQL> CREATE TABLE PRODUCTS (
PRODUCT_ID INT PRIMARY KEY,
PRODUCT_TYPE VARCHAR2(100) NOT NULL,
PRODUCT_PRICE NUMBER(6,2) NOT NULL,
PRICE_WITH_TAX AS (ROUND(PRODUCT_PRICE * 1.01, 2))
);
SQL> INSERT INTO PRODUCTS(PRODUCT_ID, PRODUCT_TYPE, PRODUCT_PRICE)
VALUES(1, 'A', 99.99);
SQL> SELECT * FROM PRODUCTS;
PRODUCT_ID PRODUCT_TYPE PRODUCT_PRICE PRICE_WITH_TAX
---------- -------------------- ------------- --------------
1 A 99.99 100.99
MySQL虚拟列:
MySQL> CREATE TABLE PRODUCTS (
PRODUCT_ID INT PRIMARY KEY,
PRODUCT_TYPE VARCHAR(100) NOT NULL,
PRODUCT_PRICE NUMERIC(6,2) NOT NULL,
PRICE_WITH_TAX NUMERIC(6,2) GENERATED ALWAYS AS
(ROUND(PRODUCT_PRICE * 1.01, 2))
);
MySQL> INSERT INTO PRODUCTS(PRODUCT_ID, PRODUCT_TYPE, PRODUCT_PRICE)
VALUES(1, 'A', 99.99);
MySQL> SELECT * FROM PRODUCTS;
+------------+--------------+---------------+----------------+
| PRODUCT_ID | PRODUCT_TYPE | PRODUCT_PRICE | PRICE_WITH_TAX |
+------------+--------------+---------------+----------------+
| 1 | A | 99.99 | 100.99 |
+------------+--------------+---------------+----------------+
1.5 MySQL和Oracle索引类型差异
1.6 MySQL和Oracle分区差异
1.7 MySQL和Oracle临时表差异
在 Oracle 中,临时表有全局临时表和session级别的临时表之分。在MySQL 中,它们简称为临时表。在这两个平台上,临时表的基本功能是相同的。不过,两者之间存在一些显著差异:
即使在数据库重启之后,Oracl