
简介瀚高数据库抽取工具面向需要将 Oracle 数据迁移或同步至瀚高HGDB数据库的运维与开发人员尤其适合数据库系统升级、主备切换及分布式部署场景。工具围绕抽取、转换、加载流程设计可自动处理两类数据库在数据类型与结构上的差异并对 Oracle 的 PL/SQL 存储过程、触发器、索引等特性做了针对性适配同时兼顾同步过程中的数据加密、错误处理与故障恢复。压缩包共 660 个文件约 55.29MB以 dll、jar、properties、exe 等程序与配置类文件为主另含大量时区数据、字体、图标及说明文本整体为依赖 JRE7 运行的完整工具目录文件名中的 10g3 也提示其对 Oracle 10g 版本做过测试优化。目前已有 778 人学习下载适合希望简化 Oracle 到瀚高迁移流程、减少手工转换与同步风险的技术人员参考使用。1. 瀚高数据库抽取工具Oracle 到 HGDB 的数据搬迁为什么总在类型和字符集上翻车上周帮一个做政务系统的朋友看数据迁移源库是跑了七八年的 Oracle目标库是瀚高数据库HGDB。他们用某款通用迁移工具跑了两轮第一轮卡在 NUMBER 精度第二轮卡在 CLOB 字段第三轮干脆在字符集上直接报错退出。这类场景里真正省事的做法不是硬啃通用工具而是用专门针对 Oracle 到 HGDB 这条链路的抽取工具——把源端对象定义、数据、约束一次性抽出来再按 HGDB 的语法和类型体系落库。这份「瀚高数据库抽取工具」就是干这个的它面向的是 Oracle 存量系统向 HGDB 迁移时最脏最累的那一段适合手里有 Oracle 老库、又要往国产库上搬的 DBA 和后端开发。下面按我实际拆包的顺序讲先讲它解决什么再讲怎么跑起来最后讲我踩过的坑。2. 抽取工具到底抽什么对象、数据、约束三条线2.1 抽取范围与 Oracle 到 HGDB 的映射逻辑很多人以为「抽取」就是把表数据导出来其实真正决定迁移成败的是对象定义先落地。Oracle 和 HGDB 虽然都走 SQL 标准但在类型体系上有明显差异Oracle 的NUMBER不带精度时是浮点语义HGDB 里对应numeric才安全VARCHAR2要落到varcharDATE在 Oracle 里带时分秒HGDB 的date只有日期必须映射到timestamp。抽取工具的第一条线就是把这些映射规则固化下来扫描源库的user_tables、user_tab_columns、user_constraints、user_indexes等字典视图生成目标端可执行的 DDL。第二条线是数据抽取。它按表分批拉取支持按 ROWID 分片避免大表一次性拉爆源库回滚段。第三条线是约束和索引主键、唯一约束、外键、普通索引分开处理因为外键在数据装载阶段通常要延后创建否则装载顺序会被卡死。我一般会先只跑对象抽取把 DDL 拿到手人工过一遍确认类型映射没问题再跑数据。这个顺序很关键DDL 错了后面全白干。2.2 连接配置与抽取任务的最小可跑示例工具本身是命令行形态配置文件驱动。下面是一个最小可跑的抽取配置源端 Oracle、目标端 HGDB只抽一张业务表做验证# extract.conf - 最小抽取配置 source.typeoracle source.host10.0.0.21 source.port1521 source.serviceORCLPDB1 source.userapp_user source.password****** source.charsetAL32UTF8 target.typehgdb target.host10.0.0.35 target.port5866 target.databaseappdb target.userhgdb_user target.password****** target.charsetUTF8 # 抽取范围schema.table多个用逗号分隔 extract.tablesAPP.T_ORDER,APP.T_ORDER_ITEM # 是否只生成DDL不导数据 extract.ddl.onlyfalse # 每批行数大表建议 5000~20000 extract.batch.size10000 # 是否按ROWID分片并行 extract.parallel.enabledtrue extract.parallel.degree4跑起来就一条命令./hg-extract -c extract.conf -o ./output -l ./logs/extract.log参数里最容易被忽略的是extract.batch.size和extract.parallel.degree。批大小太小网络往返次数多一张千万级表能跑几个小时批太大源库 undo 表空间吃紧DBA 会来找你。我的经验是单批 1 万行起步并行度不超过源库 CPU 核数的四分之一给业务留余量。extract.ddl.onlytrue是我最常用的调试开关先出 DDL 人工核对确认无误再关掉它跑全量。2.3 抽取产物结构与校验方式一次完整抽取会在输出目录下生成三类文件ddl/下是按依赖顺序编号的建表、建约束、建索引脚本data/下是按表名命名的数据文件通常是定长或分隔符格式meta/下是抽取日志和行数统计。校验的核心是行数对账源端select count(*)和目标端装载后的 count 必须一致不一致就说明有批次失败或字符截断。-- 源端行数快照抽取前执行 select table_name, num_rows from user_tables where table_name in (T_ORDER,T_ORDER_ITEM); -- 目标端装载后核对 select T_ORDER as tbl, count(*) from app.t_order union all select T_ORDER_ITEM, count(*) from app.t_order_item;注意user_tables.num_rows是统计信息可能滞后真正对账要用实时 count。我习惯在抽取前把源端实时 count 存一份到临时表装载后逐表比对差一行都要查清楚是哪批丢了。3. 类型映射与字符集两个最容易翻车的地方3.1 NUMBER、DATE、CLOB 的映射参数怎么调类型映射是抽取工具里最需要人工干预的部分。工具默认给了一套映射表但 Oracle 老库里总有些「历史遗留」写法。比如NUMBER(10,2)映射到numeric(10,2)没问题但裸NUMBER如果默认映射成numeric而不带精度某些应用写入超长小数会报错DATE默认映射成timestamp是对的但如果业务只关心日期映射成date能省空间。CLOB 更麻烦HGDB 里对应text但超大 CLOB 装载时容易触发内存问题需要走流式写入。工具支持用映射覆盖文件改默认行为# type-mapping.properties - 覆盖默认类型映射 # 裸NUMBER统一按numeric(38,10)处理避免精度丢失 NUMBERnumeric(38,10) NUMBER(*,0)numeric(38,0) DATEtimestamp CLOBtext # 指定CLOB走流式装载单字段超过10MB时启用 CLOB.stream.threshold10485760改映射的原则是「宁可宽不可窄」目标类型精度只能大于等于源端不能小于否则装载阶段截断报错而且这种错误往往在跑了几百万行之后才出现返工成本极高。CLOB 的流式阈值按实际最大字段长度设设太小会频繁走流式影响性能设太大又可能 OOM我一般先查一下源端dbms_lob.getlength的最大值再定。3.2 字符集不一致时的排查路径字符集问题是迁移里最玄学的一类数据能装进去但中文变问号或者长度校验突然超限。根因通常是源端AL32UTF8、目标端UTF8注意 HGDB 里UTF8和UTF-8不是一回事前者是服务端编码名或者反过来源端是ZHS16GBK而目标端是 UTF8一个汉字从 2 字节变 3 字节varchar(10)装 5 个汉字在源端刚好到目标端就超了。排查顺序我固定三步先确认两端实际字符集再查超长字段最后看数据内容。-- Oracle 源端字符集 select parameter, value from nls_database_parameters where parameter in (NLS_CHARACTERSET,NLS_NCHAR_CHARACTERSET); -- HGDB 目标端编码 show server_encoding; show client_encoding;如果源端是 GBK、目标端是 UTF8建表时varchar长度要按字节扩容常见做法是长度乘以 1.5 向上取整或者干脆统一放大到varchar(2*n)。这一步在 DDL 生成阶段就要处理等数据装完再改就来不及了。数据内容层面装载后用length()和octet_length()对比抽查几条中文记录能快速判断有没有截断。提示字符集转换不可逆GBK 转 UTF8 后再转回去生僻字可能已经丢了。迁移前务必在源端做一次全量备份这是唯一的后悔药。4. 避坑与排查五条血泪记录4.1 大表抽取把源库 undo 打满现象抽取跑到某张千万级表时源库告警 undo 表空间使用率 95%业务开始出现快照过旧错误。原因单批行数设得太大默认 10 万一个事务持有 undo 太久加上并行度开太高多个事务同时占用。解决把extract.batch.size降到 500010000并行度降到 24并且给抽取任务单独设一个低优先级连接避开业务高峰。我后来固定用「小批多次」策略虽然总时长略增但源库稳如老狗。4.2 外键导致数据装载顺序死锁现象数据文件按表名字母序装载子表先于父表插入时报外键约束冲突。原因抽取工具默认按表名排序输出没有考虑依赖关系。解决抽取时开启依赖分析让工具按外键依赖拓扑排序输出或者更稳妥的做法是装载阶段先禁用外键数据全部装完再统一启用并校验。后者在数据量大时更可控校验失败也能定位到具体行。4.3 空字符串与 NULL 的语义差异现象Oracle 里就是 NULL但某些中间格式导出后变成空串装到 HGDB 里成了长度为 0 的字符串导致唯一约束冲突或业务判断出错。原因Oracle 的空串语义和标准 SQL 不同导出格式没做区分。解决抽取配置里开启null.empty.as.nulltrue让工具把空串统一按 NULL 处理同时在目标端建表时对可空列不要加not null之外的额外默认值避免二次污染。4.4 索引和约束重复创建报错现象第二次跑抽取任务时目标端报「对象已存在」。原因工具默认不检查目标端已有对象DDL 脚本直接执行。解决开启ddl.if.not.existstrue让脚本带存在性判断或者每次抽取前清空目标 schema。我倾向于后者因为迁移验证阶段反复跑是常态清空重来比打补丁干净。4.5 时间戳时区偏移现象Oracle 的DATE抽出来装到 HGDB 的timestamp后时间整体偏移 8 小时。原因源端会话时区和目标端会话时区不一致抽取工具按本地时区解释。解决在源端连接串里显式指定session.timezone目标端装载前执行set timezone两端对齐到同一时区。这个坑最隐蔽因为数据「看起来」是对的只有跨天统计时才发现对不上。5. 进阶用法把抽取做成可重复的迁移流水线单次抽取跑通只是及格线真正省心的是把它做成可重复执行的流水线。我的做法是把抽取配置、类型映射、校验 SQL 全部纳入版本管理每次迁移环境变更只改配置不改脚本然后用一个包装脚本串起「抽取 → DDL 核对 → 数据装载 → 行数对账 → 抽样比对」五步。#!/bin/bash # migrate.sh - 可重复执行的迁移流水线 set -e CONF./conf/extract.conf OUT./output/$(date %Y%m%d_%H%M) # 1. 只抽DDL人工核对类型映射 ./hg-extract -c $CONF -o $OUT --ddl-only echo DDL 已生成请核对 $OUT/ddl 后按回车继续 read # 2. 全量抽取 ./hg-extract -c $CONF -o $OUT -l $OUT/extract.log # 3. 装载并校验行数 ./hg-load -c $CONF -i $OUT/data -l $OUT/load.log ./hg-verify -c $CONF -m $OUT/meta/rowcount.csv echo 迁移完成日志在 $OUT这个脚本的关键在第一步的强制停顿DDL 不核对就往下跑等于把风险留给数据阶段。行数对账那步如果失败脚本set -e会直接退出不会带着错误继续。抽样比对我一般再补一个字段级 checksum对关键业务表算md5聚合比单纯 count 更能发现内容错位。验证方法上除了行数和 checksum我还会挑三张核心表做「源端随机 100 行 vs 目标端同主键 100 行」的逐字段比对这一步能抓出类型映射导致的精度丢失比如numeric(10,2)装12345678.99被截成12345678.9。这种错误 count 和 checksum 都不一定报只有逐字段看才发现。从那以后我每次做 Oracle 到 HGDB 的迁移都强制先跑一遍 DDL-only 加人工核对再走全量最后逐字段抽样。这套流程多花半天但省下的返工时间是以周计的。希望帮到你。本文还有配套的精品资源点击获取