上一次搞 DB2 迁移到 OB 的项目还是 2021 年,OB 的第一个 DB2 (v10.5) 跟 OB 2.2 同步项目,做了很多兼容性评估和解决、数据迁移方案设计和迁移的事情。当时简单总结了《OceanBase 业务数据库实践(二)── DB2 迁移》。时隔三年又碰到 DB2 V9.7 迁移到 OB 4.2 的需求,借助于 OMS 4.2.1 产品,这次评估方案要容易得多,客户基本上可以自己动手。
OB 4.2 的 ORACLE 和 MySQL 兼容性相比早些年 V2/V3 版本已经提升很多,客观上为 DB2 业务迁移到 OB 创造有利的条件。但是 DB2 跟 ORACLE 和 MySQL 语法上一些根本性差异使得这个迁移也做不到像 ORACLE 迁移到 OB 那么丝滑。下面就分享最新的 DB2 到 OB 的迁移评估的经验。
表结构迁移考虑点。
表结构迁移方面主要看表的属性、字段类型方面的兼容。
DB2 的存储有表空间用法,这点跟 ORACLE 的表空间用法很接近,跟 MySQL 差异比较大。OB 的 ORACLE 租户支持表空间语法,不过主要是为了兼容 ORACLE,以及 OB 存储方面的一些管理,跟原本 ORACLE 或 DB2 的表空间管理目的完全不着边。DB2 里的表的表空间属性在迁移到 OB(ORACLE) 的时候可以忽略掉。二者的语法也完全不一样,所以 DB2 导出的 DDL 到 OB(ORACLE) 里改动是难免的。
接下来就看字段类型。
不管哪个数据库,都包含常用的数据类型:数值、字符串、时间(包括日期)、大对象等。就这些类型而言,DB2 语法跟 MySQL 语法是非常接近的,但是 ORACLE 语法就有很大差异。
如 DB2 里的 date 和 time 类型分别表示 日期 和 时间,但是 OB(ORACLE) 里就只有 date 类型,表示日期加时间(格式:yyyy-mm-dd hh24:mi:ss)。不过 DB2 也有 timestamp 类型,这个跟 OB(ORACLE) 是一致的。
还有 SEQUENCE 类型和自增列、生成列用法,DB2 跟 OB(ORACLE) 的用法是一致的,但 MySQL 就没有这个。
下图是客户业务某个 SCHEMA 下的表的类型迁移到 OB 的 MySQL 和 ORACLE 评估。绿色表示完全兼容,黄色表示可以兼容但不完全一样。
DB2 类型 |
OceanBase |
|
MySQL |
ORACLE |
|
DATE |
DATE |
DATE |
DBCLOB |
TEXT |
CLOB |
DECFLOAT |
DOUBLE |
NUMBER |
DECIMAL |
DECIMAL |
NUMBER |
DOUBLE |
DOUBLE |
NUMBER |
INTEGER |
INTEGER |
NUMBER |
VARCHAR | VARCHAR | VARCHAR2 |
LONG VARCHAR |
TEXT |
NUMBER |
SMALLINT |
SMALLINT |
NUMBER |
TIME |
TIME |
DATE |
TIMESTAMP |
TIMESTAMP |
TIMESTAMP |
总计 |
数据迁移考虑点
一般来说,如果类型兼容问题解决了,数据迁移应该是没有问题的。但有两个例外。
一是NULL 表示上 DB2 跟 ORACLE 有着不可调和的冲突。对 OB(ORACLE) 也一样。就 NULL 而言,二者是一致的。任何值包括 NULL 自身都不能跟 NULL 做比较运算,包括等于(=)、小于()和不等于,强行比较时其结果既不是 真(true) 也不是假(false)。NULL 代表未知,如果表的记录里有 NULL ,写 SQL 的时候就要特别注意这个特点。如果要判断列是不是 NULL 可以用 IS NULL 或 IS NOT NULL 判断,也可以通过 NVL 等函数将 NULL 转换为字符串然后再判断。这点 DB2 跟 ORACLE、MySQL 都是一致的。
不一样的地方是在 DB2 里空值('') 跟 NULL 是两个数据,空值是特殊的字符串,可以做等或不等判断。但是在 ORACLE 里空值('') 跟 NULL 是一个值。空就是 NULL,NULL 就是空。注意这里说的是空,不是空格(' ')。所以,当 DB2 里列定义是 c1 varchar(10) not null default '' 这是有意义的,但是到了 ORACLE 里虽然合法但是无意义,插入的时候还是必须得给这一列赋一个非 NULL 值。
如果是 OB(MySQL),就跟 DB2 完全一致了。MySQL 也认为 '' 跟 NULL 是两个值。这是目前遇到的数据迁移最大的困难,如果 '' 在业务上有特殊的含义,那么迁移到 OB(ORACLE) 上时,这个业务含义必须得换一个默认值了。
第二个影响数据迁移的因素就是表缺主键或唯一键。大表的全量数据迁移一般需要分批次进行,所以需要表有一个唯一性字段用于将表的数据切片。在 ORACLE 里无主键表的数据迁移是通过物理地址 ROWID 去切片的,并且 ORACLE 记录的 ROWID 发生变化的概率很低(除非 DBA 手动去 MOVE 表,即重组表)。在 DB2 里也有 ROWID 伪列,但是似乎 DB2 里这个列变化的概率还是很大( 自动的REORG 操作对 DB2 性能提升效果比较大,但是会改变记录的 ROWID 值),导致 DB2 的无主键表数据迁移困难比较大。此外无主键还会影响增量数据同步和全量数据校验的效率。所以,如果 DB2 的表要迁移到 OB(ORACLE 或 MySQL),首先建议给表增加主键或唯一键。如果业务层面没有好的主键,那就增加一个自增主键。
说到主键,就带出了 DB2 的第三个影响数据迁移的功能点。在 DB2 里加主键的时候会严格要求主键列必须都是 NOT NULL,但是在 ORACLE/OB(ORACLE) 不做这个检查,而是在写入数据的时候检查主键列的值是否包含 NULL(不允许!)。 在 DB2 里主键的值是可以包含空值(''), 联合主键列的部分列可以有很多空值('')。而到了 OB(ORACLE) 后这些值被解释为 NULL,就违反了主键列的约束定义。所以 DB2 到 OB(ORACLE) 的数据迁移逻辑里如果是先建主键,就导致记录迁移报错;如果是先迁移数据后加主键,就导致主键加不上。
SQL 兼容性分析
在 SQL 查询语法上 DB2 跟 OB(ORACLE) 更接近。DB2 跟 ORACLE 在传统行业核心业务中都大量使用,二者 SQL 语法功能非常丰富,基本上不相上下。对于同一个功能二者甚至有着一样的实现方式,我也说不清楚到底是谁参考了谁。
举几个例子。
如常见的时间函数(如 sysdate )、字符串操作函数(substr/instr/length upper/lower 等)、类型转换函数(to_date/to_char/to_timestamp) 。在 OLAP 场景,一些聚合函数、窗口函数、分析函数,OB(ORACLE) 都跟 DB2 有同名或类似的实现。
此外还有常用的分页场景。生成伪列(ROWNUM)、分页取数(FETCH FIRST n ROWS OFFSET n )等写法,DB2 跟 OB(ORACLE) 是基本一致的,在 MySQL 里就需要做相应修改。
评估/转换/迁移工具
以上是理论上分析 DB2 跟 OB(ORACLE/MySQL)的差异。实际 DB2 评估的时候一般使用 OB 推荐的 OMA 工具。不过由于 DB 9.7 版本比较老,OMA 并不支持这个版本。所以很多评估是要靠 DBA 去分析的。分析的依据就是上面提到的这些技术点。
实际工作中还常常需要将 DB2 表结构转换为 OB(ORACLE/MySQL)表结构。方法有很多种。比较土的方法是将 DB2 表结构的最简化格式导出,然后使用文本替换为 OB(ORACLE/MySQL) 的语法,删除不支持的语句。OB 企业版 OMS 里包含了一个 Java 工具 dbcat 可以做这个。dbcat 支持 DB2 9.7 版本。
配置好 JAVA_HOME 环境变量,然后执行下面命令
bin/dbcat convert -H 10.0.0.66 -P 50000 -u db2inst1 -p db2inst1 -D TPCCDB --schema TPCC --table '*' --from db2luw970 --to oboracle420
这个工具会生成一个转换后的 schema 创建脚本(.sql)以及一个 html 报告。
数据迁移就依靠 OB 企业版提供的 OMS 产品了。最新版本 4.2 的 OMS 支持 DB2 9.7 版本的数据迁移。这个数据迁移过程包括:表结构迁移、数据全量迁移、增量数据同步(包括部分 DDL同步)、全量校验、反向切换等。
DB2 增量数据同步以及 DDL 同步属于有前提条件的支持。要求 DB2 版本必须是 LUW 架构下的,且是某些常用类型的数据更新或 DDL。这里面有大量的技术细节问题(DB2 9.7 跟 10.5 的差异也很大),这也是 OMS 的 DB2 数据同步功能没有 ORACLE 那么完善的主要原因。这个就看项目里具体问题去分析了,也是最耗费时间的步骤。如果业务能从源头上避免这个数据的增量同步或增量 DDL 同步,那么数据迁移的难度会降低很多,数据迁移的效率也会 高很多。
变通经验
尽管 OMS 支持 DB2 9.7 的迁移,但是对于前面提到的空值('') 违反 NOT NULL 约束问题,OMS 并没有给出自动化的解决方案,这里就需要 DBA 手动使用 SQL 脚本批量处理。处理的事情包括:在 DB2 给表新增主键(ID 自增列)、在 OB 端将表的所有列(非主键列)都置为允许为空(NULL)、在 DB2 将主键列包含空('') 的记录修改或删除掉。
欢迎留言分享和讨论你的 DB2 迁移到 OB 的经验。
更多阅读
-
OceanBase 业务数据库实践(二)── DB2 迁移
-
OB 数据库迁移产品(OMS)实践总结
-
OB 企业版数据同步 OMS 部署实践