Oracle向瀚高数据库迁移:hgdb-extract抽取工具原理与实践

发布时间:2026/10/18 11:59:09
Oracle向瀚高数据库迁移:hgdb-extract抽取工具原理与实践 简介面向Oracle与瀚高HGDB数据库的数据迁移与同步场景瀚高数据库抽取工具以完整发布包形式提供适合需要在库表结构变更、系统升级或主备架构中保证数据一致性的DBA与数据运维人员。工具围绕抽取-转换-加载ETL流程设计针对Oracle特有对象PL/SQL存储过程、触发器、索引做了兼容处理并支持实时或定期的数据库同步降低跨库迁移的技术门槛。压缩包共660个文件、体积约55.29MB主体为jar与dll组件配合exe启动器、properties配置项和txt说明文档其中核心迁移逻辑在jar模块中dll承担底层数据库驱动与本地支持包内还带完整时区配置方便跨时区场景的时间一致性。目前已有775人学习下载部署后即可用于实际迁移任务适合需要快速完成数据迁移并关注工具稳定性与安全性的用户JRE7依赖亦已明确标注便于提前准备运行环境。1. 瀚高数据库抽取工具Oracle 存量数据往 HGDB 迁别再用 dump 硬怼国产化替换真正动手时最先卡住的往往不是新库有多难用而是旧库里那几十万行 Oracle 数据怎么体面地搬过来。瀚高数据库抽取工具下文统一叫 hgdb-extract就是专门干这件事按逻辑抽取方式把 Oracle 指定 schema 下的表结构、数据、序列读出来自动做类型换算再写入 HGDB瀚高数据库PostgreSQL 内核目标库。适合正在做 Oracle 向国产库迁移的开发者尤其是数据量大、表结构复杂、又不允许用 dmp 物理导入的场景。这篇我把它的原理、配置、实测步骤和踩过的坑一次说清。2. 抽取工具的核心机制为什么物理 dump 不能直接跨库迁2.1 异构迁移必须走逻辑抽取物理文件互读不现实Oracle 的 expdp 导出来的 dmp 是私有二进制格式里面除了数据行还夹着 Oracle 自己的控制信息、存储参数、系统编目。HGDB 虽然兼容 PostgreSQL 生态但数据页格式、事务日志、系统表结构和 Oracle 完全不同拿 dmp 文件往 HGDB 里灌第一步就会被“无法识别的文件格式”拦下来。这不是工具不给力是物理备份恢复在异构数据库之间天然走不通。常见做法有这么几条路一是手工写 SQL把每张表 SELECT 出来再 INSERT表一多脚本量爆炸类型换算还容易错二是上 CDC 同步组件重要部署采集端和投递端维护成本高适合持续增量同步不适合一次性存量搬迁三是 hgdb-extract 这种轻量抽取工具按行流式读取 Oracle 数据在内存里做类型转换后批量写入 HGDB。它面向的就是存量迁移这个单一场景跑完即走不常驻、不占额外资源。从实际对比看三种方案各有边界但一次性的全量迁移用专用抽取工具最省事。工具会把整张表在源端分页读出来目标端边建表边写数出问题能定位到具体表和行不用像手工脚本那样满屏找错。这里我一般会把源端的事务隔离级别调成只读防止抽取过程中源库有未提交事务干扰一致性。2.2 工具的默认工作流程四阶段推进拿到工具先不用急着敲命令理解它的内部流程能帮你定位 90% 的问题。hgdb-extract 默认按「连接源库 → 读取元数据 → 建表 → 流式抽取」四个阶段推进简化后的主控逻辑如下。# 简化表达工具内部四阶段主控流程 def run_extract(config): source connect_oracle(config.source) # 1. 建立源库连接只读模式 target connect_hgdb(config.target) # 2. 建立目标 HGDB 连接 metadata read_metadata(source, config.tables) # 3. 读取表结构、主键、字段顺序 ddl convert_ddl(metadata) # 4. Oracle 类型映射为 HGDB 类型 target.execute(ddl) # 5. 目标端建表可带 IF NOT EXISTS for batch in stream_rows(source, config): # 6. 按 fetch_size 分批读源数据 rows convert_rows(batch, metadata) # 7. 做类型与字符集转换 target.bulk_write(rows) # 8. 批量写入目标库并提交 target.validate_counts() # 9. 行数比对输出迁移报告逻辑说明第一步只读连接避免影响源库业务第二步和第三步把表结构先拿到内存DDL 转换在内存完成第五步建表成功后第六步开始真正搬运。注意第六步的“分批”不是按表分而是按行数分每批读取的行数由 fetch-size 控制避免一次拉全表把内存打爆。参数说明fetch_size 默认值一般是 5000但建议看表的数据宽度再调——字段宽、大对象多的表fetch_size 降到 200 更稳只有窄表纯数字和短文本才适合拉高到 10000。bulk_write 内部会用 JDBC 的批量提交每 10000 行左右 commit 一次这个值也建议按目标库磁盘 IO 调整HGDB 端 WAL 写入压力大就调小。2.3 类型映射表不是所有 Oracle 类型都能原样落地类型映射是迁移里最容易踩坑的一环。Oracle 的 NUMBER(p,s)、VARCHAR2、DATE 这几个老面孔都有对应关系但 SYS.XMLTYPE、ROWID、BINARY_FLOAT 这类 Oracle 特色类型就要小心。以下是这版工具默认的映射规则。Oracle 类型HGDB 映射类型风险等级注意事项NUMBER(p,s)NUMERIC(p,s)低精度位数一致但 NUMBER 不写 p,s 时按 NUMERIC 处理VARCHAR2(n)VARCHAR(n)低注意 HGDB 的 VARCHAR 长度按字符数算不受字节影响CHAR(n)CHAR(n)中Oracle CHAR 有尾随空格抽取时建议 TRIMDATETIMESTAMP中Oracle DATE 自带时分秒映射成 DATE 会丢时间TIMESTAMP(p)TIMESTAMP(p)低小数秒位数要显式匹配CLOBTEXT中大文本单行可能吃内存需走流式读取BLOBBYTEA高必须分块写入否则很容易 OOMRAW(n)BYTEA低长度按字节映射ROWID无映射高需要先删掉该列否则建表失败SYS.XMLTYPEXML/TEXT中建议转 TEXTHGDB 的 XML 操作函数集和 Oracle 不同映射表看下来真正需要人工干预的就是 BLOB、ROWID 和 DATE 这三种。BLOB 在 Oracle 里动辄几十 MB一次读进内存再转 BYTEAGC 都来不及回收ROWID 是 Oracle 内部物理行标识HGDB 没有对应概念抽取前要排除DATE 类型在 Oracle 的分秒信息不能丢映射成 TIMESTAMP 才能保住完整时间。做全库迁移前先拿几十张有代表性的表试跑一遍看映射日志有没有警告比一次性全量跑完再回头补要省事得多。3. 从配置到跑通一次完整的全量抽取实践3.1 前置检查三个条件不满足别开始跑HGDB 抽取工具虽然封装得比较友好但前置条件缺一不可。第一是网络连通性源 Oracle 的 1521 端口和目标 HGDB 的 5866 端口HGDB 默认端口都要能通且防火墙别拦 JDBC 长连接不然抽到一半连接被重置整批任务报错。第二是目标库权限需要目标 schema 有 CREATE TABLE、INSERT、CREATE SEQUENCE 权限工具建序列时还需要 USAGE 权限缺了会在中途报权限不足。第三是字符集源端 NLS_CHARACTERSET 最好是 AL32UTF8如果是 ZHS16GBK需要在工具配置里显式指定编码否则中文大概率乱码。检查连通性我一般直接用系统命令快速验证不用等工具报错# 源库连通性测试地址用测试网段实际环境替换为内网地址 nc -zvw 3 192.0.2.10 1521 # 目标库连通性测试 nc -zvw 3 192.0.2.20 5866逻辑说明第一条命令测 Oracle 监听端口第二条测 HGDB 端口。-w 3 表示超时 3 秒避免网络不通时长时间卡住。两个端口都通再继续否则后续配置文件里所有连接参数都白调。参数说明192.0.2.0/24 是文档保留测试网段实际环境请换成你的源库和目标库真实内网 IP。nc 命令在 Windows 下可能不存在建议直接在 Linux 跳板机上测或者用 telnet 替代。字符集这里有个特别容易翻车的点源库数据库字符集是 AL32UTF8但客户端 NLS_LANG 设置成别的JDBC 拉出来的数据在源头就乱码了。所以第二步一定要在源库跑一句SELECT USERENV(LANGUAGE) FROM DUAL;确认会话级字符集这两个字符集不一致后面工具内部转码做得再好也是白搭。3.2 全量抽取最小可跑通命令与参数说明前置检查做完开始配置抽取任务。工具的配置文件和命令行参数是拆开的连接信息放 properties 文件每次跑不同表的集合就用命令行覆盖。这是一个最小可跑通的例子。# 源库Oracle连接配置 source.jdbc.urljdbc:oracle:thin://192.0.2.10:1521/ORCL source.jdbc.userMIGRATE_USER source.jdbc.passwordEncrypted:your_password_here # 目标库HGDB连接配置 target.jdbc.urljdbc:postgresql://192.0.2.20:5866/hgdb target.jdbc.userhgdb_admin target.jdbc.passwordEncrypted:your_password_here # 抽取控制 extract.fetch.size5000 extract.parallelism4 extract.charsetAL32UTF8逻辑说明配置文件里源库走 Oracle 瘦驱动目标库走 PostgreSQL 驱动——HGDB 兼容 PG 协议所以 JDBC URL 写法是jdbc:postgresql://。password 字段工具支持明文也支持加密串生产环境建议用加密。参数说明extract.charsetAL32UTF8 表示源端数据按 UTF-8 读取这个值必须和源库 NLS_CHARACTERSET 对齐不是随便填的。extract.parallelism4 是并行抽取线程数建议先 4 后 8观察源库 CPU 和 HGDB 写入吞吐再调。注意 parallelism 不是越大越好源库是生产库时并行太猛会拖垮源库业务查询。配置就绪后执行全量抽取# 抽取 SCOTT schema 下四张表目标写入 public schema hgdb-extract --config ./extract.properties \ --schema SCOTT \ --tables DEPT,EMP,BONUS,SALGRADE \ --mode full \ --target-schema public \ --log-level INFO逻辑说明--schema 指定源库 schema--tables 指定表清单多个表用逗号分隔。--mode full 是全量模式工具会先建表再写数据。--target-schema 指定 HGDB 目标 schema不写默认同名。--log-level INFO 表示日志输出到控制台和文件方便排查。参数说明tables 参数支持通配比如EMP*会匹配 EMP 和 EMP2 这类前缀。--drop-if-exists 参数慎用它会先 DROP 目标表再重建开发环境无所谓生产环境误跑会清掉已迁移数据。跑完看日志末尾工具会输出每张表的源端行数、目标端行数和耗时三个数字对得上才算这轮迁移成功。3.3 增量抽取带时间字段的表怎么只抽变化部分全量迁移只是第一步Oracle 停更前往往还有几天增量窗口期。hgdb-extract 支持两种增量模式时间戳增量模式依赖业务表里的更新时间字段SCN 增量模式走 Oracle 闪回查询AS OF SCN不依赖业务字段。先看时间戳模式。# 增量抽取按 UPDATE_TS 字段只取 2024年5月1日 之后的变更 hgdb-extract --config ./extract.properties \ --table EMP \ --mode incremental \ --incremental-field UPDATE_TS \ --last-value 2024-05-01 00:00:00 \ --target-schema public逻辑说明--incremental-field 指定源表的时间字段--last-value 是上次抽取的截止时间。工具会生成WHERE UPDATE_TS 2024-05-01 00:00:00的查询条件只抽新增和更新的行。这里的业务逻辑是源表必须有记录更新时间的能力如果业务系统更新行时不改写 UPDATE_TS这个模式就失效。参数说明--last-value 的格式要和源表字段类型严格匹配源表是 TIMESTAMP 就写2024-05-01 00:00:00源表是 NUMBER 存储的 Unix 时间戳就写数字。增量模式下目标端写入建议配合 upsert 语义否则重复跑同一批次会产生主键冲突。SCN 模式适合源表没有可靠时间字段的场景命令如下。# SCN 增量利用闪回查询抽取不依赖业务字段 hgdb-extract --config ./extract.properties \ --table EMP \ --mode incremental \ --incremental-mode scn \ --last-scn 8438291 \ --target-schema public逻辑说明--incremental-mode scn 告诉工具走 Oracle 闪回查询--last-scn 是上次抽取结束时的 SCN 号。工具会在源端执行类似SELECT ... FROM EMP AS OF SCN 8438291的语句精确拿到这个 SCN 点的数据镜像。参数说明SCN 模式对源库有隐性要求——必须开启补充日志supplemental logging否则闪回查询可能查不到历史版本且 Oracle 的 undo 表空间大小决定闪回能追溯多远undo 不够大时 AS OF SCN 会报 ORA-01555 快照过旧。所以我一般建议能维护好 UPDATE_TS 的表优先走时间戳模式只有确实没有时间字段的表才用 SCN。4. 实测避坑四个高频翻车点与排查方法4.1 中文写入 HGDB 后全是问号两边字符集没对齐现象某公司数据迁移项目里几十万行数据抽到 HGDB 后VARCHAR2 字段里的中文全部变成????英文和数字正常。原因源头会话字符集没对齐。源库数据库字符集是 ZHS16GBK但客户端机器 NLS_LANG 设置成了 AMERICAN_AMERICA.AL32UTF8JDBC 驱动按照客户端字符集把 GBK 字节流误判成 UTF-8到工具内存里已经是乱码写进 HGDB 自然没法看。解决第一步在源库执行SELECT USERENV(LANGUAGE) FROM DUAL;把会话内字符集和数据库字符集保持一致第二步在工具的 extract.properties 里强制声明extract.charsetZHS16GBK让工具按源库实际编码读取第三步确认 HGDB 库SHOW server_encoding;是 UTF8。这三步任何一个漏了乱码都会在迁移后集中爆发。4.2 CLOB/BLOB 大批量抽取时卡死或 OOM大对象把内存撑爆了现象抽到一张带 CLOB 字段的表时工具运行十几分钟后报 OutOfMemoryErrorJVM 直接退出前面已写入的几万行数据虽然没丢但整个任务要从头再跑。原因默认 fetch-size 按行数分批每行包含一个 20MB 的 CLOB5000 行一批的理论内存占用就有 100GB任何 JVM 都扛不住。工具对 LOB 字段没有默认走流式读取这是配置问题不是工具缺陷。解决把大字段表单独拆出来跑命令里加上--fetch-size 200和--lob-mode stream。stream 模式让 CLOB/BLOB 按块从源库拉取内存占用从“整行”降为“单块”。如果一张表里有多个 BLOB 字段建议还在配置里把target.batch.commit.size从 10000 降到 1000减少单事务内的大对象数量。4.3 增量跑第二遍时主键冲突last-value 取重了现象增量任务跑了调度之后目标表出现 duplicate key value violates unique constraint 错误一查发现同一行被插了两次。原因时间戳增量模式下业务表的 UPDATE_TS 在迁移期间被更新了。比如第一次增量抽取截止到2024-05-01 00:00:00跑完后业务又更新了某行并把这个时间写成了2024-05-01 00:00:00.000第二次增量用阈值就把这行重复抽出来了。更常见的原因是工具没有内置 upsert增量批次之间天然存在主键重复风险。解决增量任务统一加上--merge-mode upsert让 HGDB 端执行INSERT ... ON CONFLICT DO UPDATE以主键为冲突键做覆盖写。这个参数默认是关闭的所以使用时要显式指定。SCN 模式下一般不存在这个问题因为 SCN 是单调递增的但同样建议加上 upsert 防手滑重放日志。4.4 分区表建表失败Oracle 的 INTERVAL 分区 HGDB 不认现象全量抽取整个 schema 时跑到某张 Oracle 分区表直接在“目标端建表”阶段报语法错误日志提示 partition boundary 表达式不兼容。原因Oracle 支持 INTERVAL 分区即自动创建未来的分区表达式写法是INTERVAL (NUMTOYMINTERVAL(1,MONTH))HGDB 继承 PostgreSQL 的分区语法只认RANGE (xxx) PARTITION BY RANGE加固定边界两边分区的声明方式完全不是一套。解决工具提供了--skip-partition参数遇到不兼容的分区表时先把分区定义跳过只建普通表并抽数据跑完后手工在 HGDB 端把 DDL 改成 PG 风格的分区表再回灌数据。我一般会先在测试环境跑一条--ddl-only命令让工具只生成 DDL 不抽数据把所有分区表的 DDL 拿过来人工审一遍改完再一起抽。5. 进阶技巧并行度调优和迁移后的校验习惯全量迁移跑通只是第一步实际项目里几千万行的表才是常态。hgdb-extract 的并行度调整有两个关键值extract.parallelism控制读源库的线程数target.batch.commit.size控制写目标库的批大小。窄表全是数字和短文本可以并行开 8、批提交 20000 行宽表带多个 CLOB/BLOB并行开 2、批提交 1000 行。调优时盯着两个指标源库的 CPU sys 占比和 HGDB 的 WAL 生成速率。WAL 增长过快说明提交太频繁批调大一点能显著降 IO。迁移完别急着收工数据校验这步懒不得。行数比对是最基本的HGDB 端和 Oracle 端各跑一句数字对上才算数-- Oracle 端计数 SELECT COUNT(*) FROM SCOTT.EMP; -- HGDB 端计数 SELECT COUNT(*) FROM public.emp;行数一致不代表内容一致我习惯再做一次抽样校验HGDB 端按随机排序取 1000 行看关键字段-- HGDB 端抽样 1000 行核对关键业务字段 SELECT EMPNO, ENAME, SAL, HIREDATE FROM public.emp ORDER BY random() LIMIT 1000;逻辑说明ORDER BY random() 是 PostgreSQL 原生的随机排序Oracle 里对应的写法是DBMS_RANDOM.VALUE两套数据库语法不同别把 Oracle 的随机函数直接搬过来。抽查的重点字段选主键、金额、日期这三类最容易曝露类型映射和时区转换问题。从那以后我每次做迁移都强制自己走完三件事先跑小表验证类型映射日志再调并行度做一次全量试迁最后用随机抽样核对关键字段。这三步看起来慢实际能省掉后面几天的返工。这个工具最值得下载的地方就是它把类型映射、增量阈值、并行参数这些迁移细节都暴露成了明确的配置项不是黑匣子——你清楚每一步在干什么出了问题也能顺着日志找回来。希望帮到你。本文还有配套的精品资源点击获取