吴海存,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 中,它们简称为临时表。在这两个平台上,临时表的基本功能是相同的。不过,两者之间存在一些显著差异:
纵然在数据库重启之后,Oracle 也会存储临时表构造供重复利用,而MySQL 仅在会话期间存储临时表。
具有相应权限的其他用户可以访问 Oracle 中的临时表。比较之下,MySQL 中的临时表只能在创建临时表的 SQL 会话期间访问。
如果在创建临时表时省略了 ON COMMIT 子句,则 Oracle 中的默认行为是 ON COMMIT DELETE ROWS,这意味着 Oracle 会在每次提交后截断临时表。比较之下,在MySQL 中,默认行为是在每次提交后保留临时表中的行。
1.8 MySQL和Oracle未利用列差异
MySQL 不支持将特定列标记为 UNUSED 的 Oracle 功能。在MySQL 中,如需从表中删除大型列并避免实行此操作时的历久待韶光,请基于原始表利用修正后的架构创建新表,然后重命名这两个表。
请把稳,此过程须要停机韶光。
1.9 MySQL和Oracle字符集差异
Oracle 和 MySQL 都供应了多种字符集、排序规则和 Unicode 编码,包括支持单字节和多字节措辞。此外,每个MySQL 数据库都可以利用自己的字符集进行配置。MySQL 中的排序规则名称以字符集名称开头,后跟一个或多个表示其他排序规则特色的结尾。所有字符集都至少包含一个排序规则(默认排序规则),但大部分字符集都具有多个支持的排序规则。请把稳,两个不同的字符集不能具有相同的排序规则。
在 Oracle 和 MySQL 中,字符集是在数据库级层指定的。与 Oracle 比较,MySQL 还支持以表级层和列级层粒度指定字符集。
1.10 MySQL和Oracle视图差异
MySQL既支持大略视图,又支持繁芜视图。在对视图实行 DML 操作时,它的行为也与 Oracle 相同。对付视图创建选项,Oracle 与MySQL 之间存在一些差异。下表着重解释了这些差异。
1.11 MySQL和Oracle数据类型差异
(可参考官方文档https://dev.MySQL.com/doc/refman/8.0/en/integer-types.html)
1.12 MySQL和Oracle内置函数差异
1.13 MySQL和Oracle自增主键和序列的差异
Oracle和MySQL除了上述数据库级别的差异外,这两种数据库在运用程序实现端也有较大的差异,比如存储过程、函数和触发器等功能的利用。在 Oracle 中,存储过程、函数和触发器归用户所有。在MySQL 中,它们归数据库所有。在MySQL 中,创建存储工具的数据库用户会自动得到 CREATE DEFINER 权限,并可以充当其他数据库用户的授权者。
1.14 MySQL和Oracle匿名块差异
PL/SQL可以在匿名块术语下运行,这意味着用户可以建立与PL/SQL引擎的连接并运行代码块,而无需创建存储工具。MySQL 没有等效的布局。在MySQL中,必须在存储过程或函数中创建代码块。
1.15 MySQL和Oracle存储过程差异
用于创建存储过程和函数的 Oracle PL/SQL命令包含可选的OR REPLACE子句,其非常适宜用于更改过程。MySQL不支持此布局。如需变动MySQL中的过程,请先利用DROP PROCEDURE再利用CREATE PROCEDURE语句。
创建MySQL存储过程或函数时,您的代码必须指定非默认分隔符“;”(分号)的其他分隔符。由于MySQL会将以 ";" 结尾的每一行视为一个新行,以是我们建议您利用不同的分隔符(如 $$)来解析所有存储过程。END$$ 关键字结束利用此分隔符。
另一个差异在于,MySQL存储过程的变量声明部分在BEGIN关键字后面进行。在Oracle中,此部分在BEGIN关键字前面进行。
1.16 MySQL和Oracle触发器差异
Oracle供应三种类型的触发器:DML触发器、instead of触发器和system event触发器。个中MySQL原生仅支持DML触发器。您可以利用FOLLOWS或PRECEDES子句来修正和链接MySQL触发器。
1.17 MySQL和Oracle默认提交办法
1.18 MySQL和Oracle事务隔离办法
事务的隔离级别可以分为四个级别
Serializable (串行化):可避免脏读、不可重复读、幻读的发生;Repeatable read (可重复读):可避免脏读、不可重复读的发生;Read committed (读已提交):可避免脏读的发生;Read uncommitted (读未提交):最低级别,任何情形都无法担保。
在MySQL数据库中,支持四种隔离级别,默认的为Repeatable read (可重复读) ;而在 Oracle数据库 中,只支持Serializable (串行化) 级别和 Read committed (读已提交) 这两种级别,个中默认的为 Read committed(读已提交) 级别,MySQL 可以设置当前系统的隔离级别,隔离级别由低到高设置依次为
set global transaction isolation level read uncommitted;set global transaction isolation level read committed;set global transaction isolation level repeatable read;set global transaction isolation level serializable;
MySQL 中利用如下语句检讨系统,会话的隔离级别
select @@global.transaction_isolation, @@session.transaction_isolation, @@transaction_isolation;
MySQL为了实现可重复读的隔离级别,InnoDB引擎利用称为“next-key locking”的算法,该算法将索引行锁定与间隙锁定结合在一起,这和隔离级别有关,只在REPEATABLE READ或以上的隔离级别下的特定操作才会有gap lock或nextkey lock。
1.19 MySQL不支持的功能项
MySQL没有并行的观点,不支持并行;MySQL优化器较弱,繁芜SQL建议拆分大略SQL;MySQL对付子查询优化不是很好;MySQL不支持归天视图、存储过程改造、同义词改造、dblink须要改造。
二、MySQL到Oracle的数据迁移办法
一样平常我们可以通过如下两种基本方法迁移数据:一次性加载和实时复制。一次性加载方法是指从 Oracle 种导涌现有数据并将其导入到 MySQL 中。实时复制方法是指数据天生之后立即从 Oracle 复制到 MySQL。
2.1 一次性加载方法
对付一次性加载方法,源数据库必须仅在该过程期间打开进行写入。因此,此方法也称为离线数据迁移。Oracle SQL DEVELOPER是用户从 Oracle 导出数据的最常用工具之一。此工具支持从采取各种格式(包括 CSV 和 SQL 插入语句)的 Oracle 表中导出数据。或者,您可以利用 SQLPlus 选择数据并设置其格式,然后将其假脱机到文件中。将数据从 Oracle 导出到平面文件后,您可以利用 LOAD DATA INFILE 命令将数据加载到 MySQL 中。该方法常日是一种最便宜的迁移方法,但它可能须要更多的手动输入,并且比利用迁移工具要慢。它还须要在迁移过程中将运用停机。
2.2 实时复制方法
实时复制方法(也称为变动数据捕获)是一种在线数据迁移方法。在初始数据复制期间,源数据库保持打开状态。复制产品会捕获源数据库上发生的数据变动,并将这些变动传输并运用到目标数据库。如果是迁移生产数据,您可以利用此方法以最大限度地减少所需的停机韶光,并确保在进行切换之前停机韶光靠近零。此方法涉及利用变动数据捕获 (CDC) 产品,例如 GoldenGate、Striim 或 Informatica 的数据复制。
2.3 遵照原则
迁移数据时,请遵照以下准则,个中大部分准则同时适用于一次性加载方法和实时复制方法:
字符集:确保源 Oracle 数据库与目标 MySQL 数据库之间的字符集兼容;外键:要提升提取速率,请暂时停用目标 MySQL 数据库上的外键限定条件。加载完成后再启用外键限定条件;索引:与外键类似,目标 MySQL 数据库上的索引可能会显著降落初始加载的速率。确保在初始加载完成之前,在目标数据库上未创建索引;Oracle 序列:MySQL 支持 AUTO_INCREMENT 而不是序列。确保在初始加载期间停用 AUTO_INCREMENT 特性,以避免覆盖 Oracle 的序列天生的值。在初始加载完成后,将 AUTO_INCREMENT 特性添加到主键列;网络连接:如果您利用的是GoldenGate TDM,请确保来源环境和目标环境都可以与GoldenGate TDM产品建立网络连接,以许可在 Oracle 端捕获数据并在MySQL 端加载数据。
在迁移过程中,字符集、空间估算、NULL值的处理、LOB迁移等,都是迁移过程中的难点,我们须要对这些难点进行剖析并设计相应的处理办法,以免在迁移过程中踩坑。
三、难点剖析和处理
3.1 字符集
对付字符集,须要考虑的问题为迁移过程字段长度匹配情形,迁移后数据是否乱码,以及迁移后字符集转换后空间的问题。
3.1.1 Oracle
Oracle创建数据库时指定字符集,一样平常不能修正,全体数据库都是一个字符集。还支持指定国家字符集,用于nvarchar2类型,常用的字符集:AL32UTF8和ZHS16GBK,个中AL32UTF8与UTF8险些是等价的。一个汉字在AL32UTF8中占三个字节,而在ZHS16GBK中占用两个字节。
3.1.2 MySQL
MySQL的字符集比较灵巧,可以指天命据库、表和列的字符集,并且很随意马虎修正数据库的字符集,不过修正字符集时已有的数据不会更新。
(1)支持的字符集:
查询支持的字符集:show character set;
个中,default collation表示默认排序规则,有_ci后缀的排序规则表示字符大小写不敏感。
(2)查看数据库的默认字符集:
show variables like ‘character_set_server’;
查询当前数据库的字符集:
show variables like ‘character_set_database’;
3.1.3 数据迁移避免乱码
客户端字符集很主要,输入数据时,包括文本输入和屏幕输入等,客户端会以这个字符集来解析输入的文本,如果实际输入的字符集与客户端字符集不一致,那么就可能导致录入数据库的数据涌现乱码;输出数据时,如果客户端字符集设置的不得当,就会导致展示或导出的数据是乱码。
Oracle 通过环境变量NLS_LANG配置客户端字符集。
Linux下会话级设置方法:export NLS_LANG=AMERICAN_AMERICA.AL32UTF8Windows下会话级设置方法:set NLS_LANG=AMERICAN_AMERICA.AL32UTF8
特殊要把稳一点,用SQLPLUS实行脚本时,NLS_LANG须要跟脚本文件的字符集保持同等。如果是UTF8,脚本须要保存为UTF8无BOM格式。
查询oracle server真个字符集: select userenv('language') from dual;
查询oracle client真个字符集:
在windows平台下,便是注册表里面相应OracleHome的NLS_LANG。可以在dos窗口里面自己设置,比如: set nls_lang=AMERICAN_AMERICA.ZHS16GBK这样就只影响这个窗口里面的环境变量。
在unix平台下,查看环境变量NLS_LANG:
echo $NLS_LANG
MySQL刻意通过如下字符集参数来确认字符集设置:
character_set_client:客户端来源数据利用的字符集;character_set_connection:连接层字符集;character_set_results:查询结果字符集。
如果检讨的结果创造server端与client端字符集不一致,请统一修正为同server端相同的字符集。
3.2 迁移过程中字段长度匹配和空间估算
MySQL中char(n)和varchar(n)代表的是字符串长度,而Oracle中char(n)和varchar(n)代表的是字节长度,以是迁移过程中可以适当减少字段长度减少储存空间。
3.3 空串和Null值的处理
Oracle和MySQL中‘’和null的差异:
从Oracle中导出到文件中是的有null值会被成‘’,这样插入到MySQL后null和‘’就会混乱,且插入到MySQL的‘’会根据不同的字段类型转换身分歧的办法。
利用文件导入到MySQL时字段中的空值null须要利用\N表示,如果用空字符串表示,那么根据不同的数据类型,MySQL处理也互异。
数据库字段如果是字符串类型,插入空时,load data 默认导入 空字符串
数据库字段如果是数字类型,插入空时,load data 默认导入 0.00000000
数据库字段如果这天期和韶光类型,插入空时,load data 默认导入 0000-00-00 00:00:00
Oracle导出到文本文件,null会变为空字符串,插入到MySQL后会被认为是空字符串插入,毁坏了数据同等性,以下供应了三种办法进行规避:
1、可以在Oracle迁移之前将所有业务表的null值变更为无意义的值,等到迁移到MySQL后统一数据修复调度回来,例如:
UPDATE SUPPLIERS_TBL SET SUPPLIER_ID=NVL(null,‘N/A’) where SUPPLIER_ID is null;
2、利用spool导出的时候对null值进行转换,须要针对表和列进行修正
SelectNVL(TO_CHAR(id),'N/A')||','||NVL(name,'N/A')||','||NVL(SEX,'N/A')||','||NVL(ADDRESS,'N/A')||','||NVL(TO_CHAR(BIRTHDAY),'N/A') from user1;
3、利用python脚本进行抽取加载,避免了导出到文本文件的问题,须要进行对脚本进行开拓,大数据量效率须要进行测试。
3.4 日期类型处理
Oracle缺省的韶光数据的显示形式,与所利用的字符集有关。一样平常显示年月日,而不显示时分秒。例如,利用us7ascii字符集(或者是其他的英语字符集)时,缺省的韶光格式显示为:28-Jan-2003,利用zhs16gbk字符集(或其他中笔墨符集)的韶光格式缺省显示为:2003-1月-28。
MySQL数据库默认韶光字段格式
以是在导出到文本文件时须要把稳,调度Oracle的默认韶光格式,最好在配置文件中直接设置
export NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'
须要把稳的点:
字段类型如果是datetime,该当严格把控相应文本数据的格式,建议采取类似这种yyyy-MM-dd HH:mm:ss同时有日期、韶光的格式,否则难以担保数据导入的精确性。
数据库字段如果是datetime,插入yyyy-MM-dd时,load data 默认导入 yyyy-MM-dd 00:00:00,数据精确性能够担保
数据库字段如果是datetime,插入HH:mm:ss时,load data 默认导入 0000-00-00 00:00:00,数据精确性不能够担保
字段类型如果是timestamp且explicit_defaults_for_timestamp=on,数据行更新时,timestamp类型字段不更新为当前韶光。
3.5 LOB字段迁移
Lob字段可以分为clob和blob。含clob字段的表可以采取UTL_FILE导出到csv中,再导入MySQL中。
参考:How to Export The Table with a CLOB Column Into a CSV File using UTL_FILE ? (Doc ID 1967617.1)
3.6 大小写敏感差异
Oracle里会默认统一按照大写来处理,MySQL里面默认是大小写敏感的。
我们较为理解的是表构造大小写敏感参数lower_case_table_names,但是数据内容区分大小写敏感参数(collate)参数利用可能较少,由于Oracle默认是区分数据大小写的,为达到迁移前后同等性,以是我们须要对这个参数做显式修正。
3.7 外部表处理办法
MySQL中供应CSV引擎,可以实现Oracle中外部表的功能,创建CSV表时,做事器将创建一个纯文本数据文件,该文件的名称以表名开头并具有.CSV扩展名。将数据存储到表中时,存储引擎会将其以逗号分隔的值格式保存到数据文件中。可以将外部文件更换.CSV后flush table实现Oracle外部表功能。
CSV引擎限定:
CSV存储引擎不支持索引;CSV存储引擎不支持分区。
利用CSV存储引擎创建的所有表必须在所有列上具有NOT NULL属性。
3.8 MySQL sql_mode
MySQL做事器能够事情在不同的SQL模式下,针对不同的客户端,以不同的办法运用这些模式。这样运用程序就能对做事器操作进行量身定制,以知足自己的需求。这类模式定义了MySQL应支持的SQL语法,以及该当在数据上实行何种确认检讨。MySQL 8.0默认为严格模式的sql_mode
sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
ONLY_FULL_GROUP_BY:sql中select后面的字段必须涌如今group by后面,或者被聚合函数包含。
STRICT_TRANS_TABLES:如果不能按照给定值插入事务表中,请中止该语句。对付非事务表,如果该值涌如今单行语句或多行语句的第一行中,则中止该语句。
NO_ZERO_IN_DATE:影响做事器是否许可年份部分非零但月份或日期部分为0的日期。
NO_ZERO_DATE:影响做事器是否许可将其 '0000-00-00'作为有效日期。厥后果还取决于是否启用了严格的SQL模式。
ERROR_FOR_DIVISION_BY_ZERO:影响除以零的处理
no_engine_subtitution:create table 中engine子句指定的存储引擎不被支持时,mysql会把表的引擎改为innodb。
建议:在导入过程中对付不匹配的格式,可以先关闭严格模式进行导入set global sql_mode='',导入之后再打开严格模式。
四、迁移性能的考虑
当数据量比较大时,我们须要着重考虑迁移的性能和速率,从而减少数据库迁移时的韶光窗口。
4.1 数据导出阶段
数据库自带一次性加载办法中卸载数据办法:
利用sql developer进行导出,运用程序只有windows版,导出数量大的表随意马虎hang;Utl_file 卸载办法 处理的表的数据量较少时较快;Sqlplus spool卸载办法 处理的表的数据量较少时较快 可以增加并行提高导出速率。
一次性加载的办法须要进行测试才能确定停机韶光
测试案例和导出韶光比拟:
或者,利用Orato8a工具将Oracle数据库的表导出成CSV文件,然后利用load命令将数据导入MySQL数据库,该工具须要预先安装好Oracle客户端,并配置好连接串。
Orato8a是一个可以快速、高效地从Oracle数据库系统中抽取数据,并将数据保存到指定文件中的专用工具。并且Orato8a还供应查询语句导出和全表导出两种办法,个中全表导出的登任命户须要对dba_extents、dba_objects和dba_tables这三张表有select权限,利用步骤如下:
迁移准备
测试Oracle数据库的连接性,有以下两种方法:
1、通过tnsnames.ora的连接串进行连接
1)修正tnsnames.ora的配置文件
vi $ORACLE_HOME/network/admin/tnsnames.ora
按照以下内容修正:
testdb_p =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = server_IP_address )(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = testdb)
)
)
解释:
1.将testdb_p可以自命名为数据库连接串名
2.将server_IP_address修正为数据库做事器的IP地址
3.将testdb修正成数据库实际的做事名
2)完成配置后,实行以下命令测试连接性:
[oracle@NODE167 output]$ sqlplus username/password@testdb_p
2、通过IP,端口号和做事名直接测试连接性
[oracle@NODE167 output]$ sqlplus username/password@server_IP_address:1521/testdb
利用orato8a导出数据
实行如下命令数据导出:
./orato8a --user=’username/password@testdb’--query=’SELECT CUSTNO, TIME FROM TEST’ --file=’/user/output/test.csv’ --field=’,’ --format=3 —parallel=4
命令解释:
--user:连接数据库的用户名,密码,连接串
--query:指定导出数据所利用的sql查询语句
--file:指定天生csv文件的路径和文件名
--field:由于是天生csv文件,以是利用半码的逗号作为分隔符
--format:设置为3时,表示将数据导出为无转义的文本格式
—parallel:并行度为4
在导出之前,建议对null值进行一些分外处理,比如可以将null值更新为与业务逻辑及数据无关的特定内容,迁移完毕后再更新成null值。
编写MySQL建表语句并建表
调度数据类型和字段长度,将Oracle数据库用的建表语句改写成MySQL数据库用的建表语句;之后登录MySQL数据库,利用改写的建表语句建表。
改写过程中的把稳事变:
1.导入导出数据时,导入/导出客户端须要设置与目标mysql数据库相同的字符集。
2.在导出之前,建议提前对null值进行一些分外处理,比如可以将null值更新为与业务逻辑及数据无关的特定内容,迁移完毕后再更新成null值,这样的方法比较安全,由于不同的数据库对null值的处理方法不一样。
现按照示例表的表构造,举出示例建表语句,供参考:
CREATE TABLE TEST_TAB (CUSTNO VARCHAR(10),
TIME VARCHAR(20)
);
数据导入MySQL
MGR架构下实行以下命令:
mysqlsh --uri root@server28:3306 —ssl-mode=DISABLED -- util import-table
/data/raid/data/190513newdata/data03/pdcrFile --schema=PDS --table=PDCR
--fieldsTerminatedBy=”,” --bytes-per-chunk=10M
或者可以利用python利用已有的包进行迁移普通表,测试参考,性能须要进行测试。
#Import librariesimport cx_Oracleimport mysql.connectorimport pandas as pdfrom sqlalchemy import create_engine#Set Oralce Connectionconn = cx_Oracle.connect('test/test@192.168.19.111/orcl')#Open cursorcursor = conn.cursor()#buidling sql statement to select records from Oraclesql = "SELECT FROM T"#read data into dataframe directlydata=pd.read_sql(sql,conn)print("Total records form Oracle : ", data.shape[0])#Create sqlalchemy engineengine = create_engine("mysql+mysqlconnector://test:root@192.168.19.111:3312/test")data.to_sql("t", con = engine, if_exists = 'append', index = False, chunksize =10000)print("Data pushed success")#close connectionconn.close()
4.2 数据导入阶段
数据导入我们可以采取mysqlsh或者load data进行导入,在导入数据的时候预先的修正一些参数,来获取最大性能的处理,比如可以把自适应hash关掉,Doublewrite关掉,然后调度缓存区,log文件的大小,把能变大的都变大,把能关的都关掉来获取最大的性能,我们接下来说几个常用的:
innodb_flush_log_at_trx_commit
如果innodb_flush_log_at_trx_commit设置为0,log buffer将每秒一次地写入log file中,并且log file的flush(刷到磁盘)操作同时进行。该模式下,在事务提交时,不会主动触发写入磁盘的操作。如果innodb_flush_log_at_trx_commit设置为1,每次事务提交时MySQL都会把log buffer的数据写入log file,并且flush(刷到磁盘)中去。如果innodb_flush_log_at_trx_commit设置为2,每次事务提交时MySQL都会把log buffer的数据写入log file。但是flush(刷到磁盘)的操作并不会同时进行。该模式下,MySQL会每秒实行一次 flush(刷到磁盘)操作。
把稳:由于进程调度策略问题,这个“每秒实行一次 flush(刷到磁盘)操作”并不是担保100%的“每秒”。
sync_binlog
sync_binlog 的默认值是0,像操作系统刷其它文件的机制一样,MySQL不会同步到磁盘中去,而是依赖操作系统来刷新binary log。当sync_binlog =N (N>0) ,MySQL 在每写N次 二进制日志binary log时,会利用fdatasync()函数将它的写二进制日志binary log同步到磁盘中去。
注:如果启用了autocommit,那么每一个语句statement就会有一次写操作;否则每个事务对应一个写操作。
max_allowed_packet
在导大容量数据特殊是CLOB数据时,可能会涌现非常:“Packets larger than max_allowed_packet are not allowed”。这是由于MySQL数据库有一个别系参数max_allowed_packet,其默认值为1048576(1M),可以通过如下语句在数据库中查询其值:show VARIABLES like '%max_allowed_packet%'; 修正此参数的方法是在MySQL文件夹找到my.cnf文件,在my.cnf文件[MySQLd]中添加一行:max_allowed_packet=16777216
innodb_log_file_size
InnoDB日志文件太大,会影响MySQL崩溃规复的韶光,太小会增加IO包袱,以是我们要调度得当的日志大小。在数据导入时先把这个值调大一点。避免无谓的buffer pool的flush操作。但也不能把 innodb_log_file_size开得太大,会明显增加 InnoDB的log写入操作,而且会造成操作系统须要更多的Disk Cache开销。
innodb_log_buffer_size
InnoDB用于将日志文件写入磁盘时的缓冲区大小字节数。为了实现较高写入吞吐率,可增大该参数的默认值。一个大的log buffer让一个大的事务运行,不须要在事务提交前写日志到磁盘,因此,如果你有事务比如update、insert或者delete 很多的记录,让log buffer 足够大来节约磁盘I/O。
innodb_buffer_pool_size
这个参数紧张缓存InnoDB表的索引、数据、插入数据时的缓冲。为InnoDB加速优化紧张参数。一样平常让它即是你所有的innodb_log_buffer_size的大小就可以,再导入阶段innodb_log_file_size越大越好。
innodb_buffer_pool_instances
InnoDB缓冲池拆分成的区域数量。对付数GB规模缓冲池的系统,通过减少不同线程读写缓冲页面的争用,将缓冲池拆分为不同实例有助于改进并发性。
4.3 迁移后验证数据的完全性
在数据迁移完毕后,我们须要找出目标 MySQL库存在的问题和数据不一致的地方,以便快速办理数据之间的所有差异。可以考虑从如下几个方面进行验证:
比较源数据库表与目标数据库表的行数以找出所有差距,除了运行count之外,还要对同一组表运行sum、avg、min和max;针对目标MySQL环境运行常用的SQL语句,以确保数据与源Oracle数据库匹配;将运用连接到源数据库和目标数据库,并验证结果是否匹配。
五、迁移总结
1、明确数据构造差异,运用实现的差异并精确调度是保障迁移后准确性的关键。
2、得当的迁移办法须要再多次测试演习训练中进行摸索才能在相对准确的韶光内完成迁移,一定要选择较得当的迁移方法。
3、比较推举利用mysqlsh将csv导入到MySQL库中,该方法可以并行导入且可以将大的数据文件进行切片。
4、数据库迁移完毕后,数据完全准确的考验非常主要,迁移前须要制订合理的完全性校验步骤和方法。
关注"大众号【dbaplus社群】,获取更多原创技能文章和精选工具下载
Gdevops广州站:解答2021运维、数据库、金融科技亟待决议的三大问题