OceanBase 业务数据库实践(三)── DB2 迁移 2

2024年 4月 28日 19.4k 0

上一次搞 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 部署实践

    相关文章

    pt-kill工具的使用
    pt-ioprofile工具包的使用
    数据库管理-第216期 Oracle的高可用-01(20240703)
    DBMS_REPAIR EXAMPLE SCRIPT WITH PARTITION
    数据库事务的四大特性: ACID 
    使用BBED修复损坏的SYSTEM文件头

    发布评论