作者:郑增权,爱可生 DBA 团队成员,OceanBase 和 MySQL 数据库技术爱好者。
爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
本文约 2400 字,预计阅读需要 8 分钟
客户存在将 PolarDB PostgreSQL[1] 11.9 (下文以 polardb_pg 代称) 迁移至 OceanBase[2] 4.2.1.10 Oracle (下文以 ob_oracle 代称)租户的需求。
当前 OMS[3] 暂不支持此功能,需要人工迁移,本文将描述迁移的整体思路以及相关的问题处理,为异构数据库之间的迁移方案设计提供参考。
PolarDB PostgreSQL 版本是在 PostgreSQL 数据库的基础上构建的,下文的部分处理步骤会将其视作 PostgreSQL 看待。
表结构 + 全量数据迁移 + 全量数据校验
dbcat[4] 版本:2.1.1
dbcat 可转换的对象范围(polardb_pg -> ob_oracle):表结构、视图、序列,其他对象暂不支持。
ob_oracle 端权限[6] 分为"对象权限"和"系统权限"两大类,而 polardb_pg 端权限[7] 分类则更多一些。
请根据机器实际内存进行调整。
-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"
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
dbcat 表结构转换时外键与表结构同时生成在一个文件,外键不应在数据迁移前创建,会导致数据迁移出错。
将外键从表结构文件中提取并保存到其他文件。
方式一:若外键数量少,且关联的表数据量小,在迁移完数据之后可以直接进行创建,示例如下:
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;
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)
源端将其改造为 bigint 再通过 dbcat 转换。
如下示例中,(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)
OceanBase 数据库中没有 oid 这种存储对象的唯一标识符,在 dbcat 转换完的文件中直接移除这一类索引。
dbcat 会将 polardb_pg 中的 boolean 字段转成 ob_oracle 端的 NUMBER(1),polardb_pg 端给 boolean 赋值可能是(t,f,n),迁移数据时,尝试往 NUMBER(1) 插入 (t,f,n)会因为字段属性不符而报错。
select id from table1 where flag = t;
需改成(加上单引号):
select id from table1 where flag = 't';
请根据机器实际内存进行调整。
-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)
特殊事项:联合主键不符合 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"
}
}
}
]
}
}
本文的数据迁移任务,分为主任务和多个子任务,主任务是所有需迁移的表的汇总项,子任务是每个表一个任务,启动主任务之后会自动拉起子任务,子任务会按照配置文件依次执行。
DataX 迁移数据时存在某些数据无法迁移,但是不会报错终止任务而是反复重试的行为,这会导致持续打印无效日志占用空间,且阻碍后续任务运行。
引入监控脚本,在 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分钟
参考资料
[1]
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
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有