
作者:郑增权,爱可生 DBA 团队成员,OceanBase 和 MySQL 数据库技术爱好者。
爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
本文约 2400 字,预计阅读需要 8 分钟。

1. 背景
客户存在将 PolarDB PostgreSQL[1] 11.9 (下文以 polardb_pg 代称) 迁移至 OceanBase[2] 4.2.1.10 Oracle (下文以 ob_oracle 代称)租户的需求。
当前 OMS[3] 暂不支持此功能,需要人工迁移,本文将描述迁移的整体思路以及相关的问题处理,为异构数据库之间的迁移方案设计提供参考。
PolarDB PostgreSQL 版本是在 PostgreSQL 数据库的基础上构建的,下文的部分处理步骤会将其视作 PostgreSQL 看待。
2. 步骤概览
迁移范围
表结构 + 全量数据迁移 + 全量数据校验
迁移步骤分工
dbcat[4] 版本:2.1.1
dbcat 可转换的对象范围(polardb_pg -> ob_oracle):表结构、视图、序列,其他对象暂不支持。
用户迁移:人工创建 角色迁移:脚本处理 权限迁移:脚本处理 表结构迁移:dbcat 工具 视图迁移:dbcat 工具 序列迁移:dbcat 工具 外键迁移:dbcat 工具 + 脚本处理 其他对象迁移:业务侧自行迁移 数据迁移:DataX[5] 数据校验:脚本处理
3. 用户迁移
polardb_pg 的一个用户可以对应多个 schema。 ob_oracle 租户的一个用户只能对应一个 schema(即,用户名就是 schema)。 当 polardb_pg 迁移至 ob_oracle 时,一般而言,polardb_pg 端的 schema_name = ob 端的用户名。 特殊项: PUBLIC 等 OB 端默认角色不可作为 OB 端的用户名,需改成新的用户名。 polardb_pg 待迁移用户拥有的角色也需要迁移至 ob_oracle 端。
4. 权限转换
ob_oracle 端权限[6] 分为"对象权限"和"系统权限"两大类,而 polardb_pg 端权限[7] 分类则更多一些。
权限转换思路
相同的权限无需转换,直接授权即可。 polardb_pg 端特有的权限,在 ob_oracle 端授予相近的权限,或组合权限以实现对应的功能。 比如 polardb_pg 端的 TRUNCATE 权限,在 ob_oracle 端则是用户拥有表的 DROP 权限就可以进行 TRUNCATE TABLE 操作。
5. 表结构转换
5.1 dbcat 转换效率提升
请根据机器实际内存进行调整。
-Xms8G
:初始堆内存为 8GB。-Xmx16G
:最大堆内存为 16GB。
[root@evan_zheng-server bin]# grep Xms dbcat
JAVA_OPTS="$JAVA_OPTS -Xms8G -Xmx16G -XX:+UseG1GC -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M"
5.2 引号问题
5.2.1 问题描述
dbcat 转换默认会将 库名、表名、列名、约束名 带上双引号。 若在 ob_oracle 端执行 DDL 带上双引号会严格保留双引号中指定的格式(包括大小写),可能导致执行 SQL 时发生找不到表、列等问题。
5.2.2 解决方法
dbcat 转换时加上 --no-quote
可以产生不带引号的 DDL 语句,示例如下:
dbcat convert -H 10.186.64.61 -P 5432 -u $pg_user -p $password -D postgres --schema $schema --from pgsql11 --to oboracle420 --no-quote --table '*' -f dbcat_path > dbcat_all_tables_$(date +%Y%m%d_%H%M%S).log 2>&1
5.3 外键
5.3.1 问题描述
dbcat 表结构转换时外键与表结构同时生成在一个文件,外键不应在数据迁移前创建,会导致数据迁移出错。
5.3.2 解决方法
将外键从表结构文件中提取并保存到其他文件。
方式一:若外键数量少,且关联的表数据量小,在迁移完数据之后可以直接进行创建,示例如下:
ALTER TABLE $pg_user.$table_name ADD CONSTRAINT "$fk_name" FOREIGN KEY ("$fk_column") REFERENCES $pg_user.$table_name ("$primary_column");
方式二:若外键数量多,且关联的表数据量大,可以通过 ENABLE NOVALIDATE (不检查现有数据是否满足外键条件,新插入或更新的数据必须遵守外键约束。)格式快速创建外键,示例如下:
ALTER TABLE $pg_user.$table_name ADD CONSTRAINT "$fk_name" FOREIGN KEY ("$fk_column") REFERENCES $pg_user.$table_name ("$primary_column") ENABLE NOVALIDATE;
5.4 包含 oid 字段属性的表
5.4.1 问题描述
polardb_pg 存在一种 PostgreSQL数据库 特有的数据类型 oid,包含 oid 字段属性的表无法通过 dbcat 转换,dbcat 在转换表结构时会直接将表忽略,表结构示例如下:
column_name | data_type | character_maximum_length | is_nullable | column_default | primary_key
-----------------------+-----------------------------+--------------------------+-------------+----------------+---------------------
id | character varying | 36 | NO | | PRIMARY KEY (id)
content | oid | | YES | |
(2 rows)
5.4.2 解决方法
源端将其改造为 bigint 再通过 dbcat 转换。
5.5 基于 oid 创建的索引
5.5.1 问题描述
如下示例中,(oid): 表示索引是基于表的 oid 列创建的。oid 通常是 PostgreSQL 中的一种特殊列类型,用于存储对象的唯一标识符,一般由 PostgreSQL 数据库自动生成。
schemaname | tablename | indexname | tablespace | indexdef
------------+--------------------------+-------------------------+------------+------------------------------------------------------------------------------
$schema | $table_name | pg_oid_12345_index | | CREATE UNIQUE INDEX pg_oid_12345_index ON $schema.$table_name USING btree (oid)
5.5.2 解决方法
OceanBase 数据库中没有 oid 这种存储对象的唯一标识符,在 dbcat 转换完的文件中直接移除这一类索引。
5.6 boolean 字段转换
5.6.1 问题描述
dbcat 会将 polardb_pg 中的 boolean 字段转成 ob_oracle 端的 NUMBER(1),polardb_pg 端给 boolean 赋值可能是(t,f,n),迁移数据时,尝试往 NUMBER(1) 插入 (t,f,n)会因为字段属性不符而报错。
5.6.2 解决方法
在 ob_oracle 目标端将 NUMBER(1) 替换为 CHAR(5) 以提高字段兼容性 程序代码需做调整,比如原本查询语句是:
select id from table1 where flag = t;
需改成(加上单引号):
select id from table1 where flag = 't';
6. DataX 数据迁移
6.1 DataX 迁移效率提升
6.1.1 DataX 配置参数
请根据机器实际内存进行调整。
-Xms16g
:初始堆内存为 16GB。-Xmx32g
:最大堆内存为 32GB。
grep "DEFAULT_JVM" opt/module/datax/bin/datax.py | grep "Xms"
DEFAULT_JVM = "-Xms16g -Xmx32g -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=%s/log" % (DATAX_HOME)
6.1.2 DataX json 配置参数
参数根据实际调整,关键配置作出注释。 有主键的表需指定 splitPK。
特殊事项:联合主键不符合 json 文件格式,需当作无主键表迁移。
{
"job": {
"setting": {
"speed": {
// 控制数据传输速度
"channel": 32// 并发通道(线程)数;值越大并行度越高,但可能增加资源压力
},
"errorLimit": {
"record": 1000, // 允许的最大错误记录数,超过则作业失败
"percentage": 0// 允许的错误记录百分比(0 表示不按百分比限制)
}
},
"content": [
{
"reader": {
// 数据源(读取数据)的配置
"name": "postgresqlreader",
"parameter": {
"username": "$pg_user",
"password": "$password",
"column": ["id", "version"],
"connection": [
{
"table": ["$schema.$table_name"],
"jdbcUrl": ["jdbc:postgresql://10.186.64.61:5432/postgres?useUnicode=true&characterEncoding=utf8"]
}
],
"splitPK": "id"// 数据分片主键,用于并行读取(按 id 分片)
}
},
"writer": {
// 数据目标(写入数据)的配置
"name": "oceanbasev10writer",
"parameter": {
"obWriteMode": "insert",
"column": ["id", "version"],
"connection": [
{
"table": ["$table_name"],
"jdbcUrl": "jdbc:oceanbase://10.186.64.161:2883/$schema_name?useLocalSessionState=true&allowBatch=true&allowMultiQueries=true&rewriteBatchedStatements=true"// OceanBase JDBC 连接字符串,包含批量操作优化参数
}
],
"username": "SYS@ora_tenant#cluster",
"password": "$password",
"writerThreadCount": 10, // 写入线程数,控制写入并行度
"batchSize": 1000, // 每批次写入的记录数,优化性能
"memstoreThreshold": "0.9"
}
}
}
]
}
}
6.2 数据迁移异常时的处理机制
6.2.1 问题描述
本文的数据迁移任务,分为主任务和多个子任务,主任务是所有需迁移的表的汇总项,子任务是每个表一个任务,启动主任务之后会自动拉起子任务,子任务会按照配置文件依次执行。
DataX 迁移数据时存在某些数据无法迁移,但是不会报错终止任务而是反复重试的行为,这会导致持续打印无效日志占用空间,且阻碍后续任务运行。
6.2.2 解决方法
引入监控脚本,在 OB 端间隔一秒查询一次当前迁移的表和行数,当发现当前迁移的表 5 分钟内行数没有变化时,会自动 kill 掉对应的子任务进程并记录到日志,示例如下:
[2025-04-17 10:23:18] ------------------------
[2025-04-17 10:23:24] 开始检查
[2025-04-17 10:23:24] 总表数量: 4454
[2025-04-17 10:23:24] 当前表: $table_name
[2025-04-17 10:23:24] 第 4228 个表
[2025-04-17 10:23:24] (OB数据库)查询记录数: 0
[2025-04-17 10:23:24] 检查表行数和kill卡住的表_脚本执行剩余时间: 55小时 11分钟
7. 性能监控
PolarDB PostgreSQL 数据库的平台监控。 OceanBase 数据库的 OCP 平台监控。 主机资源监控。
8. 结论
异构数据库迁移需考虑两者差异性,测试环境中进行方案验证,再在生产环境进行实施和优化,建议生产环境至少进行一至两轮模拟迁移之后再正式进行割接。 非增量迁移,为保证数据一致性,停业务并锁定两端用户后再迁移数据。
PolarDB PostgreSQL 版: https://www.aliyun.com/product/apsaradb/polardbpg
[2]OceanBase 企业版: https://www.oceanbase.com/product/oceanbase
[3]OceanBase Migration Service: https://www.oceanbase.com/product/oms
[4]dbcat: https://www.oceanbase.com/docs/enterprise-oceanbase-database-cn-1000000000749015
[5]DataX: https://github.com/alibaba/datax
[6]ob_oracle 端权限: https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000220864
[7]polardb_pg 端权限: https://help.aliyun.com/zh/polardb/polardb-for-oracle/warpaman72ax09gk
本文关键字:#OceanBase# #PolarDB# #数据迁移# #dbcat# #DataX#


✨ Github:https://github.com/actiontech/sqle
📚 文档:https://actiontech.github.io/sqle-docs/
💻 官网:https://opensource.actionsky.com/sqle/
👥 微信群:请添加小助手加入 ActionOpenSource
🔗 商业支持:https://www.actionsky.com/sqle






