Oracle数据库恢复工具FGODU(FGEDU Oracle DUL)
FGODU (全称:FGEDU Oracle DUL) 是一个 Oracle 数据库数据恢复与抽取工具,用于在数据库无法正常启动的情况下,不依赖 Oracle 实例,直接从数据文件中读取并提取数据。支持字典模式与非字典模式,支持 ASM/裸设备/UDEV/LVM 等多种存储类型,跨平台支持 Linux 与 Windows。
目录
关于作者
| 联系方式 | 信息 |
|---|---|
| 作者 | 风哥 |
| 官方网站 | http://www.fgedu.net.cn , http://www.itpux.com |
如果您在使用过程中遇到问题、需要商业技术支持、或希望参与贡献,欢迎通过上方联系方式与作者取得联系。
1. 程序介绍
1.1 概述
FGODU 是一个离线 Oracle 数据抽取工具(DUL = Data UnLoader),它直接读取 Oracle 数据文件(.dbf)的二进制内容,解析数据块格式,提取表结构和行数据,而不需要启动 Oracle 数据库实例。
这意味着即使数据库因以下原因无法启动,FGODU 仍然可以恢复数据:
- 控制文件损坏或丢失
- SYSTEM 表空间损坏
- 参数文件(spfile/pfile)损坏
- 联机日志文件丢失
- 数据库软件损坏
- 操作系统无法启动 Oracle 进程
- 服务器硬件报废但磁盘仍可读
- 误删库、错删表后没有可用备份
FGODU 的核心设计目标就是 “成为 DBA 的最后一根救命稻草”:当备份失效、归档缺失、数据库完全无法 MOUNT 时,只要还有数据文件(或 ASM 磁盘)可读,FGODU 就能直接从磁盘层面把表数据读出来,恢复为 Oracle 原生兼容的 DMP / SQL*Loader / SQL 等格式,导入到任何 Oracle 目标库中。FGODU 具有以下独特优势:
- 完全开源,白盒可控:源代码完全公开,无任何隐藏逻辑与后门,政企客户可自行审计安全
- 部署极简,单文件:一个
fgodu二进制即可运行,不依赖 Oracle 客户端,不安装 JRE/.NET/任何库 - 跨平台 + 低 GLIBC 依赖:Linux 版仅依赖 GLIBC_2.2.5 / 2.3,可直接拷贝到 RHEL 5~10、国产麒麟/UOS/欧拉 等任意系统
- 自动双格式 DMP 输出:根据目标 Oracle 版本(9i → 26ai)自动切换传统 exp/imp 与 Data Pump expdp/impdp 格式
- 智能坏块 + 空行过滤:自动跳过磁盘坏块与 DELETE 残留的无效行,内置主键去重,输出干净可直接入库
1.2 与 Oracle 原生工具的区别
| 特性 | FGODU | exp/expdp | RMAN |
|---|---|---|---|
| 需要 Oracle 实例运行 | 否 | 是 | 是 |
| 需要 Oracle 软件安装 | 否 | 是 | 是 |
| 数据库无法启动时可用 | 是 | 否 | 部分 |
| SYSTEM 损坏时可用 | 是(非字典模式) | 否 | 否 |
| 恢复已删除数据 | 是 | 否 | 否 |
| 跨平台部署 | 是(单二进制) | 否 | 否 |
| 读取 ASM 磁盘 | 是 | 通过实例 | 是 |
1.3 适用场景
- 数据库无法启动:控制文件、SYSTEM 表空间、参数文件损坏
- 误删除数据恢复:DELETE/DROP/TRUNCATE 后的数据恢复
- 数据迁移:将数据从损坏的数据库迁移到新环境
- 数据审计:从数据文件中提取历史数据
- 坏块处理:跳过坏块,最大程度恢复可用数据
- ** ASM 磁盘恢复**:ASM 磁盘组无法 mount 时的数据恢复
2. 功能特性
2.1 核心功能
FGODU 的核心功能围绕 “在 Oracle 实例无法运行的情况下,直接从磁盘把数据捞回来” 这一本质目标展开,每一项功能都是作者在数百次真实故障恢复场景中反复打磨出来的,而非纸面设计:
| 功能 | 说明 |
|---|---|
| 数据文件直读 | 直接以只读方式打开 Oracle 数据文件,绕过 Oracle 实例。即使数据库 MOUNT 失败、控制文件损坏,只要 .dbf 文件本身可读,FGODU 就能从文件头、数据块中提取信息。全程使用 O_RDONLY 打开,绝对不会对原始数据文件造成二次写入。 |
| 字典模式 | 利用 Oracle 数据字典(SYSTEM 表空间中的 tab 、 c o l 、col 、col、seg 、 u s e r 、user 、user、ts 、 u e t 、uet 、uet 等核心表)自动发现全部用户表、列结构和区映射。这是最推荐的模式,只要 SYSTEM 完好,FGODU 能自动把数据库里所有 schema、所有表都枚举出来,省去人工定义的繁琐。 |
| 非字典模式 | SYSTEM 表空间严重损坏、无法引导字典时的 “兜底” 模式。用户通过 define table 语句手动定义表结构和列类型,FGODU 根据已知的 dataobj# 或直接暴力扫描,把匹配的行数据从磁盘上挖出来。即使 SYSTEM 全坏,也能保住核心业务表。 |
| ** ASM 支持** | 直接读取 ASM 磁盘组,支持 oracleasm、udev 规则命名、LVM 逻辑卷、raw 裸设备、EMC PowerPath 多路径等多种在生产环境中常见的存储方式。对存储透明,DBA 无需先手工把 ASM 拷贝成文件系统文件再恢复。 |
| 块级解析 | 完整实现 Oracle 数据块格式解析,包括缓存头(cache header)、ITL 事务槽、行目录、行头、列偏移表、NULL 列压缩等;同时提供块 checksum 校验、损坏检测、跨块行链接(chained rows / migrated rows)的拼接处理,确保最大限度捞回每一行。 |
| 数据类型解码 | 支持 NUMBER、VARCHAR2、CHAR、DATE、TIMESTAMP、RAW、LOB、ROWID、UROWID、LONG、BFILE、INTERVAL 等所有 Oracle 常用与高基数数据类型的内部二进制解码,并按 Oracle 官方格式正确输出。 |
2.2 高级功能
在核心抽取能力之外,FGODU 还提供了面向 “疑难杂症” 的高级恢复功能,这些功能往往是商业 DUL 才具备的能力:
| 功能 | 说明 |
|---|---|
| 删除数据恢复 | 支持 DELETE、DROP、TRUNCATE 三种常见误操作后的数据恢复。DELETE 场景利用已删除行在行目录中仍保留的 flag=0x20 标记抓取;TRUNCATE 场景通过扫描段原高水位线下的空余区间恢复;DROP 场景通过匹配 obj#/dataobj# 定位回收站与残留段。 |
| 块大小自动检测 | 自动识别 Oracle 所有支持的块大小 2K/4K/8K/16K/32K/64K/128K,并根据数据文件头 (V1/V2/V3 header) 智能识别。对于头损坏无法识别的极端情况,也支持通过 set db_block_size 手动指定。 |
| 多输出格式 | SQL INSERT、CSV、TXT、DMP(exp/imp 与 expdp/impdp 双格式)、SQL*Loader 共 5 种主流输出格式。从可人工审核的文本到 Oracle 原生二进制,从 ETL 工具友好到 100% 批量导入,覆盖几乎所有下游数据再利用场景。 |
| 跨平台兼容 | Linux (RHEL 5~10、CentOS、OEL、Ubuntu、SUSE、国产系统) 与 Windows 原生双版本,32 位 / 64 位架构均可运行。Linux 便携版在构建时对 GLIBC 版本做符号版本降级,确保一份二进制跑遍新旧系统。 |
| ** LOB 提取** | 支持 BLOB/CLOB/NCLOB 三类大对象,包括 inline LOB(直接存储在行中)与 out-of-row LOB(存储在 LOB 段),以及带 CHUNK / PCTVERSION / SECUREFILE / BASICFILE 的不同格式。 |
| UNDO 回滚 | 从 UNDO 表空间中读取前镜像(Before Image),把被 UPDATE 覆盖的数据、被 DELETE 删除的数据重新找回,特别适合 DELETE 未 commit 但 DBWR 已写盘、或数据库异常崩溃后事务未清理的场景。 |
| 压缩块处理 | 支持 Oracle 压缩特性:OLTP 压缩(Advanced Row Compression)、Query 压缩(Hybrid Columnar Compression Warehouse)、Archive 压缩,对压缩块先解压再抽取。 |
| 蛮力扫描 | 没有字典信息、没有 SYSTEM 表空间、甚至不知道块归属时的终极手段。对所有数据文件逐块扫描,根据行内列分布特征去匹配目标表结构,把能匹配上的行全部吐出来。 |
| 多线程 | 内置线程池支持并行扫描与并行写出。默认用 CPU 核数/2 作为线程数,也可 set parallel auto / set parallel 8 手动调整。大表 / 大文件场景下吞吐相比单线程提升 3~6 倍。 |
| RAC 支持 | 支持 Oracle RAC 集群环境。即使 RAC 所有节点同时宕机、CRS/GI 无法启动,只要从共享存储中取出各节点的 datafile,FGODU 就能合并读取并恢复完整数据。 |
| 坏块跳过 | 内置 checksum 校验 + 尾部标记校验,一旦发现磁盘介质损坏的块(corrupt block),自动标记并跳过,绝不因一块坏数据导致整张表恢复失败;同时统计坏块位置、数量,供 DBA 后续分析。 |
| 进度显示 | 实时显示进度条、已处理块数 / 总块数、处理速度(MB/s、rows/s)、剩余时间预估。让运维工程师在面对几十 GB / 几 TB 的数据恢复时心里有数,而不是 “黑屏等半天”。 |
| 字符集自适应 | 自动从 bootstrap$ / props$ 中检测出源数据库字符集 (NLS_CHARACTERSET) 与国家字符集 (NLS_NCHAR_CHARACTERSET),在输出 DMP / SQL 时保持原始编码,避免乱码。 |
| 主键去重 | 基于主键列值做去重。同一数据块可能保留 UPDATE 前后的多个版本,FGODU 在输出阶段会按主键分组,保留最新或完整的一条,避免导入后出现重复行。 |
| 空行过滤 | DELETE / UPDATE 操作后,原有的行空间不会被物理清零,只是行头 flag 标记 delete+lock。FGODU 内置 is_empty_row 与 flag 判断,把这种"行壳子"过滤掉,输出文件里没有垃圾数据。 |
2.3 输出格式详解
FGODU 支持多种输出格式,每种格式适用于不同的导入场景:
2.3.1 SQL INSERT 格式 (set output_format sql)
生成标准 INSERT 语句,可直接在目标数据库执行:
INSERT INTO SCOTT.EMP (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO)
VALUES (7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 800, NULL, 20);
适用场景:小数据量恢复、需要人工审核数据内容
2.3.2 CSV 格式 (set output_format csv)
逗号分隔值格式,通用兼容性:
EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO
7369,SMITH,CLERK,7902,1980-12-17,800,,20
适用场景:导入到 Excel、其他数据库、ETL 工具
2.3.3 TXT 格式 (set output_format txt)
制表符分隔格式,适合人工查看:
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
7369 SMITH CLERK 7902 1980-12-17 800 20
2.3.4 SQL*Loader 格式 (set output_format sqlldr)
生成 SQL*Loader 兼容的 CTL + 数据文件:
LOAD DATA
INFILE *
INTO TABLE SCOTT.EMP
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
TRAILING NULLCOLS
(
EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO
)
BEGINDATA
7369,"SMITH","CLERK",7902,"1980-12-17",800,,20
适用场景:大规模数据导入,Oracle 9i~26ai 全版本兼容
2.3.5 DMP 二进制格式 (set output_format dmp)
生成 Oracle 原生二进制 DMP 文件,根据目标 Oracle 版本自动选择格式:
| Oracle 版本 | DMP 格式 | 导入工具 | 命令 |
|---|---|---|---|
| Oracle 9i | exp/imp 二进制格式 | imp | imp userid=user/pass@db file=X.dmp tables=T ignore=y |
| Oracle 10g+ | Data Pump expdp/impdp 格式 | impdp | impdp userid=user/pass@db directory=DP_DIR dumpfile=X.dmp tables=T |
版本切换命令:
fgodu> .set oracle_version 9i # 生成 exp/imp 格式(用 imp 导入)
fgodu> .set oracle_version 10g # 生成 expdp/impdp 格式(用 impdp 导入)
fgodu> .set oracle_version 11g # 生成 11g 兼容的 expdp/impdp 格式
DMP 文件结构(exp/imp 格式):
[文件头记录] version + charset_name + charset_id + ncharset + db_name
[DDL 记录] CREATE TABLE 文本
[数据记录] INSERT 文本 + 类型规范 + 二进制行 + 0xFFFF
[EOF 标记] 0x00000000
DMP 文件结构(Data Pump 格式):
[文件头块] [4字节大小][4字节类型=1][version+charset 信息]
[XML 元数据块] [4字节大小][4字节类型=3][XML DDL]
[数据块] [4字节大小][4字节类型=4][二进制行数据]
[EOF 块] [4字节大小=0][4字节类型=5]
重要提示:
- Oracle Data Pump 是闭源专有格式
- 如果
impdp导入报 ORA-39002/ORA-39070 错误,请改用以下方案之一:- 使用
imp工具(Oracle 10g 仍支持):.set oracle_version 9i重新生成 - 使用 SQL*Loader 格式(100% 标准兼容):
set output_format sqlldr
- 使用
3. 支持环境
3.1 支持的 Oracle 版本
从 9i 一直到最新的 26ai,FGODU 兼容 Oracle 所有主流版本。不同版本在块格式、压缩算法、数据字典结构上存在差异,FGODU 均已在内核层面适配;尤其值得注意的是 DMP 输出格式会根据目标版本自动切换——9i 输出传统 exp/imp 格式,10g 及以上自动输出 Data Pump expdp/impdp 格式:
| 版本 | 发布年份 | 支持状态 | DMP 导出格式 | 导入工具 | 核心备注 |
|---|---|---|---|---|---|
| Oracle 9i R2 (9.2.0.x) | 2002 | 完全支持 | exp/imp 二进制 | imp |
传统格式,所有 Oracle 版本的 imp 工具均可导入 |
| Oracle 10g R2 (10.2.0.x) | 2005 | 完全支持 | Data Pump expdp/impdp | impdp |
首次引入 Data Pump |
| Oracle 11g R2 (11.2.0.x) | 2009 | 完全支持 | Data Pump expdp/impdp | impdp |
目前存量最大的版本 |
| Oracle 12c R1/R2 (12.1/12.2) | 2013/2016 | 完全支持 | Data Pump expdp/impdp | impdp |
多租户 CDB/PDB,12cR2 引入 Identity 列 |
| Oracle 18c (18.3/18.4) | 2018 | 完全支持 | Data Pump expdp/impdp | impdp |
年度发布模型首版 |
| Oracle 19c (19.3+) | 2019 | 完全支持 | Data Pump expdp/impdp | impdp |
Oracle 长期支持版,当前企业主流 |
| Oracle 21c (21.3) | 2021 | 完全支持 | Data Pump expdp/impdp | impdp |
创新发行版 |
| Oracle 23c (23.2+) | 2023 | 完全支持 | Data Pump expdp/impdp | impdp |
免费开发者版 + JSON 关系融合 |
| Oracle 26ai | 2026 | 完全支持 | Data Pump expdp/impdp | impdp |
带 AI 向量检索的最新版 |
3.2 支持的操作系统
FGODU 使用标准 C11 编写,依赖最少的系统库(libc + pthread),所以能在非常广泛的 Linux 发行版和 Windows 上运行。Linux 便携版只依赖 GLIBC_2.2.5 / GLIBC_2.3 / GLIBC_2.3.2,这意味着哪怕是十多年前的 RHEL 5,也能直接拷贝二进制运行,无需重新编译:
| 家族 | 发行版 | 版本 | 架构 | 备注 |
|---|---|---|---|---|
| RHEL / OEL | Red Hat Enterprise Linux | 5 / 6 / 7 / 8 / 9 / 10 | x86_64 / aarch64 | 完全支持 |
| Oracle Linux | 5 / 6 / 7 / 8 / 9 / 10 | x86_64 / aarch64 | 完全支持,含 UEK 内核 | |
| CentOS / Rocky / Alma | CentOS | 5 / 6 / 7 / 8 / 9 | x86_64 | 完全支持 |
| Rocky Linux | 8 / 9 | x86_64 / aarch64 | 完全支持 | |
| AlmaLinux | 8 / 9 | x86_64 / aarch64 | 完全支持 | |
| 国产系统 | 银河麒麟 Kylin V10/V11 | V10 SP1/SP2 / V11 | x86_64 / 飞腾 / 鲲鹏 | 完全支持,已在多个政企项目实测 |
| 统信 UOS 服务器版 | 20 / 23 | x86_64 / 鲲鹏 / 飞腾 | 完全支持 | |
| 欧拉 openEuler | 20.03 LTS SP3 / 22.03 LTS | x86_64 / aarch64 / riscv64 | 完全支持 | |
| 龙蜥 Anolis OS | 7 / 8 / 9 | x86_64 / aarch64 | 完全支持 | |
| Debian / Ubuntu | Ubuntu Server LTS | 16.04 / 18.04 / 20.04 / 22.04 / 24.04 | x86_64 / aarch64 | 完全支持 |
| Debian | 8 (Jessie) ~ 12 (Bookworm) | x86_64 / aarch64 | 完全支持 | |
| SUSE | SUSE Linux Enterprise Server | 11 SP4 / 12 SP5 / 15 SP5+ | x86_64 / aarch64 | 完全支持 |
| Windows 桌面 | Windows | XP / Vista / 7 / 8 / 10 / 11 | x86 / x86_64 | 完全支持 |
| Windows Server | Windows Server | 2003 / 2008 / 2012 / 2016 / 2019 / 2022 | x86 / x86_64 | 完全支持 |
3.3 支持的存储类型
对于数据文件在磁盘上如何呈现给 FGODU,工具对所有常见的存储形态都做了适配。对用户而言,多数情况下直接写路径即可,FGODU 会根据路径模式自动判断存储类型:
| 存储类型 | 示例路径 | 自动识别模式 | 说明 |
|---|---|---|---|
| 文件系统(FILE) | /oradata/fgedudb/system01.dbf |
是 | 最常见;标准文件 IO,预读 + mmap 加速 |
| ASM (oracleasm) | /dev/oracleasm/disks/DATA_0001 |
是 | Oracle ASMLib 驱动的字符设备接口 |
| UDEV 命名的 ASM | /dev/asm-disk1、/dev/disk/by-id/scsi-3xxx |
是 | udev 规则持久化命名,替代 oracleasm |
| LVM 逻辑卷 | /dev/mapper/vg_data-lv_oradata |
是 | Linux LVM2 逻辑卷,可跨过多个 PV |
| Linux 裸设备 | /dev/raw/raw1 |
是 | 老系统使用 raw 设备绑定的裸盘 |
| 通用块设备 | /dev/sda1、/dev/vdb |
是 | KVM / Xen / 物理服务器的标准块设备 |
| EMC PowerPath | /dev/emcpowera1 |
是 | EMC 存储的多路径驱动 |
| 其他多路径(device-mapper) | /dev/mapper/mpath0p1 |
否,手动指定 lvm 或 raw |
DM-Multipath 生成的聚合设备 |
| AIX LVM / HP-UX VG | /dev/rvg01/rlv_oradata |
否,手动指定 raw |
小型机场景,使用字符设备模式读取 |
3.4 硬件与资源要求
FGODU 本身是个非常轻量的二进制(Linux 版仅 ~250KB),但面对几十 GB / 几 TB 的数据文件恢复时,对硬件资源有一定要求。以下给出一个经验参考值:
| 资源 | 最低配置 | 推荐配置(1TB 以内) | 推荐配置(1TB~10TB) |
|---|---|---|---|
| CPU | 2 核 | 8 核 | 16 核 以上 |
| 内存 | 1 GB | 8 GB | 32 GB |
| 可用磁盘空间 | 数据文件总大小的 1.5×(给输出留空间) | 数据文件总大小的 2× | 数据文件总大小的 2×(建议 SSD) |
| 磁盘 IO | 普通 SATA | SSD 或 RAID10 | 高速 SSD / NVMe |
| 运行用户权限 | 对数据文件的读权限 | root 或 oracle 用户 | root 用户(避免设备权限问题) |
| 网络 | 不需要(离线工具) | 1 Gbps(若要远程拷贝 DMP) | 10 Gbps(远程拷贝大文件) |
内存说明:
- 字典模式下,FGODU 会把数据字典(OBJ$ / COL$ / SEG$ / UET$)全部缓存在内存中,通常占用 50MB ~ 500MB 就足够了
- 但如果启用蛮力扫描、UNDO 回滚、LOB 提取,会额外使用 IO 缓存
- 建议给 FGODU 留 4GB 以上可用内存,避免因 OS 页缓存不足导致读取变慢
磁盘说明:
- 原始数据文件只读打开,不占用写入 IO
- 但 DMP / SQL 输出会持续写入,所以输出目录建议放在 SSD 上
- 如果数据文件 + 输出目录在同一块磁盘,会产生随机读 + 顺序写的争抢,IOPS 会低不少
3.5 字符集支持
FGODU 会在 bootstrap 阶段自动从 sys.props$ 读取源数据库字符集 (NLS_CHARACTERSET) 与国家字符集 (NLS_NCHAR_CHARACTERSET),全程保持原始编码写入输出文件,避免乱码。导入时只需设置 NLS_LANG 与源端一致即可。下表列出全部已验证的字符集:
| Oracle 字符集名 | 语言/地区 | 编码 | 常见场景 |
|---|---|---|---|
AL32UTF8 |
全球多语言 | UTF-8 | 9i+ 默认推荐,支持所有 Unicode 字符 |
UTF8 |
全球多语言 | UTF-8 (CESU-8) | 8i/9i 遗留 Unicode 字符集 |
ZHS16GBK |
简体中文 | GBK / GB2312 | 国内最常见的中文字符集(老库) |
ZHS32GB18030 |
简体中文 | GB18030 | 国产合规项目指定字符集 |
ZHT16BIG5 |
繁体中文 | BIG5 | 台湾 / 香港老项目 |
ZHT16HKSCS |
繁体中文 | HKSCS | 香港增补字符集 |
ZHT32EUC |
繁体中文 | EUC-TW | 台湾繁体 EUC 格式 |
WE8ISO8859P1 |
西欧 | ISO-8859-1 (Latin-1) | 欧洲老项目 |
WE8MSWIN1252 |
西欧 | Windows-1252 | 西欧 Windows 平台默认 |
WE8DEC |
西欧 | DEC-MCS | Digital / OpenVMS 遗留 |
US7ASCII |
纯英文 | ASCII 7-bit | 极简场景 |
EE8MSWIN1250 |
中东欧 | Windows-1250 | 东欧 Windows 平台 |
CL8MSWIN1251 |
俄语 | Windows-1251 | 俄罗斯 / 独联体 |
EL8MSWIN1253 |
希腊语 | Windows-1253 | 希腊 |
AR8MSWIN1256 |
阿拉伯语 | Windows-1256 | 中东阿拉伯语 |
JA16SJIS |
日语 | Shift-JIS | 日本 Windows 项目 |
JA16EUC |
日语 | EUC-JP | 日本 Unix 项目 |
JA16UTF16 |
日语 NCHAR | UTF-16BE | 日本常用 NCHAR 字符集 |
KO16KSC5601 |
韩语 | KSC5601 (EUC-KR) | 韩国项目 |
KO16MSWIN949 |
韩语 | Unified Hangul Code (UHC) | 韩国 Windows 项目 |
TH8TISASCII |
泰语 | TIS-620 | 泰国项目 |
VN8MSWIN1258 |
越南语 | Windows-1258 | 越南项目 |
WE8EBCDIC37 |
EBCDIC 大型机 | IBM-037 | AS/400、z/OS EBCDIC |
WE8EBCDIC1047 |
EBCDIC OpenEdition | IBM-1047 | z/OS USS 常见 |
对于上表未列出的字符集,FGODU 会以 “二进制不做转换” 模式透传——也就是说,只要 NLS_LANG 设置正确,导入后依然能正确还原,不会出现"字符集转换错误导致整列 NULL"的情况。
3.6 数据类型支持
下表列出 FGODU 当前版本在解码、输出(SQL / CSV / TXT / sqlldr / DMP 双格式)阶段均完整支持的数据类型清单,以及部分受限支持的类型:
| 分类 | 数据类型 | 支持状态 | 说明 / 限制 |
|---|---|---|---|
| 字符串 | CHAR(n) |
✅ 完全支持 | 0~2000 字节 |
VARCHAR2(n) |
✅ 完全支持 | 0~4000 字节(12c 可扩展至 32767) | |
NCHAR(n) |
✅ 完全支持 | NLS_NCHAR_CHARACTERSET 字符集 | |
NVARCHAR2(n) |
✅ 完全支持 | NLS_NCHAR_CHARACTERSET 字符集 | |
LONG |
✅ 完全支持 | 最长支持 2GB,分块读出;输出时转 VARCHAR2 大字段或保留 LONG | |
| 数值 | NUMBER(p,s) |
✅ 完全支持 | p: 0~38, s: -84~127,完整保留 Oracle 内部精度(不转浮点) |
FLOAT(n) |
✅ 完全支持 | Oracle 内部仍以 NUMBER 存储,完整读出 | |
BINARY_FLOAT |
✅ 完全支持 | IEEE-754 单精度 | |
BINARY_DOUBLE |
✅ 完全支持 | IEEE-754 双精度 | |
| 日期时间 | DATE |
✅ 完全支持 | 世纪/年/月/日/时/分/秒 7 字节 |
TIMESTAMP(n) |
✅ 完全支持 | 精度 0~9,支持小数秒 | |
TIMESTAMP(n) WITH TIME ZONE |
✅ 完全支持 | 含 TZH:TZM 时区偏移 | |
TIMESTAMP(n) WITH LOCAL TIME ZONE |
✅ 完全支持 | 以 UTC 存储,按源数据库时区还原 | |
INTERVAL YEAR(n) TO MONTH |
✅ 完全支持 | 年-月 间隔 | |
INTERVAL DAY(n) TO SECOND(m) |
✅ 完全支持 | 日-秒 间隔 | |
| 二进制 | RAW(n) |
✅ 完全支持 | 0~2000 字节,输出为十六进制字符串 |
LONG RAW |
✅ 完全支持 | 最长 2GB,十六进制输出 | |
| LOB | BLOB |
✅ 完全支持 | inline(<4000 字节行内)+ out-of-row(LOB 段独立块)均支持 |
CLOB |
✅ 完全支持 | 单字节 / 多字节字符集均可,保留字符编码 | |
NCLOB |
✅ 完全支持 | 使用 NLS_NCHAR_CHARACTERSET 解码 | |
BFILE |
⚠️ 受限支持 | 仅能读取 BFILE 指针(directory alias + filename),文件本身不在数据文件中 | |
| 行/地址 | ROWID |
✅ 完全支持 | 扩展 ROWID:OOOOOO.FFF.BBBBBB.RRR |
UROWID |
✅ 完全支持 | IOT 表逻辑 ROWID | |
| 其他 | XMLType (object-relational) |
✅ 完全支持 | 底层 CLOB/XMLType 存储,按 CLOB 读出 |
JSON (12c+ OSON 格式) |
⚠️ 受限支持 | 以底层 CLOB 文本方式读取,保留 JSON 原文 | |
SDO_GEOMETRY (Oracle Spatial) |
⚠️ 受限支持 | 对象类型按 ADT 结构解析,可展开列数据 | |
| 不支持 | ANYDATA / ANYTYPE |
❌ 不支持 | 通用封装类型 |
| 用户自定义 ADT / VARRAY / Nested Table | ❌ 不支持 | 复杂嵌套对象(普通对象部分场景可展开) |
4. FGODU程序使用
4.1 安装构建
4.1.1 环境要求
Linux:
- GCC 4.8+ 或兼容编译器
- Make
- glibc-static(可选,用于完全静态构建)
Windows:
- Visual Studio 2015+ (MSVC) 或 MinGW
- NMAKE(随 Visual Studio 附带)
4.1.2 构建命令
Linux 构建:
# 获取源码
git clone https://github.com/fgedu/fgodu.git
cd fgodu
# 默认构建(便携版,推荐)
make
# 构建 Debug 版本 (调试用)
make debug
# 构建完全静态版本(需要 glibc-static)
make static
# 安装到系统
make install
Windows 构建:
# 方式1:使用 MSVC (Visual Studio 命令行)
nmake -f Makefile.win
# 方式2:使用 MinGW (Windows 上)
mingw32-make -f Makefile.win CC=gcc
# 方式3:从 Linux 交叉编译 Windows 版本 (需要 mingw32-gcc)
make mingw
4.1.3 构建选项
| 命令 | 说明 | 输出文件 |
|---|---|---|
make |
默认 - 便携版,静态链接 libgcc/libstdc++ | build/portable/fgodu |
make debug |
调试构建,含符号 | build/debug/fgodu |
make portable |
便携版,仅依赖 GLIBC_2.2.5/2.3 | build/portable/fgodu |
make release |
优化构建,动态链接 | build/release/fgodu |
make static |
完全静态链接(需要 glibc-static) | build/static/fgodu |
make mingw |
Windows 交叉编译(需要 mingw32-gcc) | build/mingw/fgodu.exe |
nmake -f Makefile.win |
Windows 原生编译(MSVC) | build_win/fgodu.exe |
4.1.4 跨平台部署
Linux 便携版部署(推荐):
make # 构建便携版
# 在目标系统上直接运行
scp build/portable/fgodu user@target:/tmp/
ssh user@target "/tmp/fgodu -v"
便携版特性:
- 静态链接 libgcc 和 libstdc++
- 仅依赖 GLIBC_2.2.5、GLIBC_2.3 和 GLIBC_2.3.2
- 可直接复制到任何 Linux 系统运行
- 支持 RHEL5/6/7/8/9/10、Oracle Linux、Ubuntu、SUSE、国产操作系统等
Windows 版部署:
# 方式1: 从 Linux 交叉编译
make mingw
# 将 build/mingw/fgodu.exe 复制到 Windows 服务器
# 方式2: 在 Windows 上编译
nmake -f Makefile.win
# 将 build_win/fgodu.exe 复制到目标服务器
# 在 Windows 上运行
C:\fgodu\fgodu.exe
Windows 版特性:
- 支持 XP/Vista/7/8/10/11、Server 2003-2022
- 功能与 Linux 版完全一致
- 仅支持文件系统存储模式(不支持 ASM)
- 路径使用反斜杠
\分隔
4.2 启动方式
4.2.1 交互式模式
# 直接启动
./fgodu
# 启动后显示:
FGODU - FGEDU Oracle DUL v1.0.0
Running on: Oracle Linux 9 (x86_64 (AMD64))
Kernel: 5.15.0-200.131.27.el9uek.x86_64
========================================
FGODU - FGEDU Oracle DUL v1.0.0
Type 'help' for available commands.
fgodu>
4.2.2 命令行模式
# 使用配置文件
./fgodu -c control.cfg
# 执行单条命令
./fgodu -e "datafile 1 /oradata/fgedudb/system01.dbf"
# 全功能模式(需要密码)
./fgodu -all
# 然后输入密码:
# 显示版本信息
./fgodu -v
# 显示帮助
./fgodu -h
全局选项:
| 选项 | 说明 |
|---|---|
-c <config> |
指定配置文件 |
-e <command> |
执行单条命令并退出 |
-all |
启用全功能模式(需输入密码) |
-v |
显示版本信息 |
-h |
显示帮助 |
全功能模式说明:
默认模式下,FGODU 限制每表最多恢复 100 行数据。使用 ./fgodu -all 并输入密码 `` 可解除限制:
$ ./fgodu -all
Enter password for full access:
Full access mode enabled.
FGODU - FGEDU Oracle DUL v1.0.0
fgodu>
4.3 命令详解
快捷别名
| 别名 | 对应命令 |
|---|---|
add / a |
datafile |
boot / b |
bootstrap |
ls |
show |
desc |
describe |
get |
unload |
find |
scan |
def |
define |
rcv |
recover |
chk |
check |
cfg |
set |
exit / q |
quit |
? |
help |
4.3.1 set - 设置参数
# 设置数据库块大小(默认自动检测)
fgodu> set db_block_size 8192
# 设置数据库名称
fgodu> set db_name ORCL
# 设置输出格式(sql/csv/txt/dmp/sqlldr)
fgodu> set output_format dmp
# 设置输出目录
fgodu> set output_dir /tmp/recovery
# 设置并行线程数
fgodu> set parallel 8
# 设置是否跳过坏块
fgodu> set skip_bad_blocks yes
# 设置目标 Oracle 版本(影响 DMP 格式)
fgodu> .set oracle_version 11g
4.3.2 datafile - 添加数据文件
# 添加文件系统数据文件(自动检测类型)
fgodu> datafile 1 /oradata/fgedudb/system01.dbf
# 添加裸设备
fgodu> datafile 2 /dev/raw/raw1 raw
# 添加 ASM 磁盘(oracleasm)
fgodu> datafile 3 /dev/oracleasm/disks/DATA01 asm
# 添加 UDEV 设备
fgodu> datafile 4 /dev/disk/by-id/scsi-xxx udev
# 添加 LVM 设备
fgodu> datafile 5 /dev/mapper/vg_data-lv_oradata lvm
存储类型自动检测规则:
| 路径模式 | 自动识别类型 |
|---|---|
/dev/oracleasm/ |
ASM |
/dev/asm- |
ASM |
/dev/mapper/ |
RAW |
/dev/raw/ |
RAW |
/dev/emcpower |
RAW |
/dev/disk/ |
RAW |
/dev/sd* |
RAW |
| 其他文件路径 | FILE |
4.3.3 bootstrap - 引导数据字典
# 引导数据字典(需要先添加 SYSTEM 表空间数据文件)
fgodu> bootstrap
# 引导所有字典信息(包括 COL$ 列元数据)
fgodu> boot all
引导流程:
Step 1: 读取 SYSTEM 表空间文件头 (#0块)
↓ 定位 bootstrap$ 地址
Step 2: 读取 bootstrap$ (obj#=17)
↓ 获取核心字典表的物理位置
Step 3: 加载核心字典表 (obj$, tab$, col$, user$, ts$, seg$, uet$, fet$)
↓
Step 4: 构建内存字典缓存
↓
Step 5: 根据 tab$+col$ 获取用户表结构
↓
Step 6: 根据 seg$+uet$ 获取表的物理存储位置
↓
Step 7: 逐个区、逐个块提取数据
4.3.4 show - 显示信息
# 显示数据库信息
fgodu> show db
# 显示表空间列表
fgodu> show tablespaces
fgodu> show ts
# 显示用户列表
fgodu> show users
# 显示指定用户的表
fgodu> show tables SCOTT
# 显示所有表
fgodu> show tables
# 显示列信息
fgodu> show columns
4.3.5 describe - 查看表结构
fgodu> describe SCOTT.EMP
fgodu> desc SCOTT.EMP
4.3.6 unload - 卸载数据
# 卸载指定表(字典模式)
fgodu> unload table SCOTT.EMP
# 卸载整个用户的数据(生成批量导入脚本 import_all.sql)
fgodu> unload user SCOTT
# 卸载整个表空间的数据
fgodu> unload tablespace USERS
# 暴力卸载(离线模式,无字典)
fgodu> unload brute 2 EMP 7369
卸载完成后输出示例:
[1/1] SCOTT.EMP obj#=7369 dataobj#=7369 columns=8 (found 14 rows)
exp/imp DMP file created:
Dump: /tmp/recovery/SCOTT_EMP.dmp
Rows: 14
Import: imp userid=... file=/tmp/recovery/SCOTT_EMP.dmp tables=EMP
4.3.7 recover - 恢复删除数据
# 恢复 DELETE 删除的数据(需要字典模式)
fgodu> recover deleted SCOTT.EMP
# 恢复 TRUNCATE 删除的数据
fgodu> recover truncated 0 3 7369 EMP
# 自动检测模式:
fgodu> recover truncated EMP
# 恢复 DROP 删除的数据
fgodu> recover dropped 0 EMP
# 自动检测模式:
fgodu> recover dropped EMP
# 扫描所有数据文件恢复所有可恢复数据
fgodu> recover all
# 扫描指定块范围恢复数据
fgodu> recover range 2 100 200 EMP
4.3.8 其他命令
# scan - 扫描数据
fgodu> scan extents
fgodu> scan table SCOTT.EMP
fgodu> scan all 2 EMP
# check - 检查数据文件
fgodu> check datafile 1
# dump - 转储块内容
fgodu> dump header 1 1
fgodu> dump block 1 100
# asm - ASM 管理
fgodu> asm discover
fgodu> asm mount DATA
fgodu> asm ls
# define - 非字典模式定义表
fgodu> define table EMP (EMPNO NUMBER(4), ENAME VARCHAR2(10))
# query - 查询对象信息
fgodu> query SCOTT.EMP
fgodu> query all
fgodu> query tablespace
# quit - 退出
fgodu> quit
4.4 配置文件
使用 control.cfg 配置文件启动:
# ============================================================
# FGODU 配置文件示例 (control.cfg)
# 使用方法: ./fgodu -c control.cfg
# ============================================================
[database]
db_name = ORCL
db_block_size = 8192
[output]
output_format = dmp
output_dir = /tmp/fgodu_recovery
include_columns = yes
sql_escape = yes
charset =
[performance]
num_threads = 4
progress_interval = 1000
use_compression = no
[recovery]
recover_deleted = yes
skip_bad_blocks = yes
undo_rollback = no
handle_compressed = yes
extract_lob = yes
handle_chained_rows = yes
brute_force = no
[asm]
scan_path =
au_size = 1048576
[logging]
log_level = info
log_file =
show_stats = yes
[datafiles]
datafile.1.path = /oradata/fgedudb/system01.dbf
datafile.1.type = file
datafile.2.path = /oradata/fgedudb/users01.dbf
datafile.2.type = file
4.5 设置参数详解
数据库参数
| 参数 | 值范围 | 默认值 | 说明 |
|---|---|---|---|
db_name |
字符串 | 自动检测 | 数据库名称 |
db_block_size |
2048~131072 | 自动检测 | 数据库块大小(字节) |
输出参数
| 参数 | 值范围 | 默认值 | 说明 |
|---|---|---|---|
output_format |
sql/csv/txt/dmp/sqlldr | dmp | 输出格式 |
output_dir |
路径 | 当前目录 | 输出目录 |
oracle_version |
9i/10g/11g/12c/18c/19c/21c/23c/26ai | 11g | 目标 Oracle 版本(影响 DMP 格式) |
charset |
字符集名 | 自动检测 | 输出字符集 |
性能参数
| 参数 | 值范围 | 默认值 | 说明 |
|---|---|---|---|
parallel |
auto/1~128 | CPU/2 | 并行线程数 |
skip_bad_blocks |
yes/no | yes | 是否跳过坏块 |
5. Oracle恢复案例场景与操作过程
案例 1: Oracle数据库无法启动 - 字典模式恢复
场景:数据库因控制文件丢失无法启动,但数据文件完好
操作步骤:
# 步骤 1: 创建数据文件列表
cat > files.txt <<EOF
1 /oradata/fgedudb/system01.dbf
2 /oradata/fgedudb/sysaux01.dbf
3 /oradata/fgedudb/undotbs01.dbf
4 /oradata/fgedudb/users01.dbf
EOF
# 步骤 2: 启动 FGODU(自动加载 files.txt)
./fgodu
# 步骤 3: 引导数据字典
fgodu> bootstrap
# 步骤 4: 查看数据库信息
fgodu> show db
fgodu> show tablespaces
fgodu> show users
# 步骤 5: 设置输出参数
fgodu> set output_format dmp
fgodu> set output_dir /tmp/recovery
fgodu> .set oracle_version 11g
# 步骤 6: 提取单表数据
fgodu> unload table HR.EMPLOYEES
# 步骤 7: 按用户批量导出(自动生成 import_all.sql)
fgodu> unload user HR
# 步骤 8: 退出
fgodu> quit
导入到新数据库:
# 设置字符集环境变量
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
# 方法1: 使用 impdp (10g+ DMP 格式)
sqlplus hr/hr@newdb @import_all.sql
# 或单独导入
impdp userid=hr/hr@newdb directory=DATA_PUMP_DIR \
dumpfile=HR_EMPLOYEES.dmp tables=EMPLOYEES
# 方法2: 使用 imp (9i exp/imp 格式)
# 先设置 .set oracle_version 9i 重新生成
imp userid=hr/hr@newdb file=HR_EMPLOYEES.dmp tables=EMPLOYEES ignore=y
# 方法3: 使用 SQL*Loader (100% 兼容)
sqlldr hr/hr@newdb control=HR_EMPLOYEES.ctl log=import.log
案例 2: Oracle DELETE 误删除数据恢复
场景:用户误执行 DELETE FROM EMP 删除了大量数据,未 COMMIT 但数据已写入 UNDO
操作步骤:
./fgodu
fgodu> datafile 1 /oradata/fgedudb/system01.dbf
fgodu> datafile 2 /oradata/fgedudb/undotbs01.dbf
fgodu> datafile 3 /oradata/fgedudb/users01.dbf
fgodu> bootstrap
# 恢复 DELETE 删除的数据
fgodu> recover deleted SCOTT.EMP
输出:
Recovering deleted rows from SCOTT.EMP...
Recovered 100 deleted rows.
案例 3: Oracle TRUNCATE 表恢复(自动检测模式)
场景:表被意外 TRUNCATE,不知道表在哪个数据文件
操作步骤:
./fgodu
fgodu> datafile 1 /oradata/fgedudb/system01.dbf
fgodu> datafile 2 /oradata/fgedudb/users01.dbf
fgodu> bootstrap
# 自动检测模式 - 扫描所有数据文件
fgodu> recover truncated EMP
输出:
Auto-detection mode: searching for truncated table EMP...
Scanning all datafiles for recoverable blocks...
Scanning datafile 1...
Scanning datafile 2...
Found 1000 recoverable rows
Recovered 1000 rows.
案例 4: Oracle SYSTEM 表空间损坏 - 非字典模式
场景:SYSTEM 表空间严重损坏,无法引导字典
操作步骤:
./fgodu
fgodu> datafile 1 /oradata/fgedudb/users01.dbf
fgodu> set db_block_size 8192
# 手动定义表结构
fgodu> define table EMP (EMPNO NUMBER(4), ENAME VARCHAR2(10), JOB VARCHAR2(9),
MGR NUMBER(4), HIREDATE DATE, SAL NUMBER(7,2),
COMM NUMBER(7,2), DEPTNO NUMBER(2))
# 设置数据对象号(如果已知)
fgodu> set dataobj_num 7369
# 蛮力扫描
fgodu> scan all 1 EMP
# 暴力提取
fgodu> unload brute 1 EMP 7369
案例 5: Oracle ASM 磁盘组无法 mount
场景:ASM 磁盘组无法 mount,但磁盘完好
操作步骤:
./fgodu
fgodu> asm discover
fgodu> datafile 1 /dev/oracleasm/disks/DATA_0001 asm
fgodu> bootstrap
fgodu> show tables SCOTT
fgodu> unload table SCOTT.EMP
案例 6: Oracle全库数据导出迁移
场景:数据库无法启动,需要迁移整个数据库到新服务器
操作步骤:
# 创建导出脚本
cat > full_export.sh <<'EOF'
#!/bin/bash
OUTPUT_DIR="/tmp/fgodu_full_export_$(date +%Y%m%d_%H%M%S)"
mkdir -p $OUTPUT_DIR
./fgodu <<FGODU_EOF
bootstrap
set output_format dmp
set output_dir $OUTPUT_DIR
.set oracle_version 11g
unload user SCOTT
unload user HR
unload user OE
unload user SH
quit
FGODU_EOF
EOF
chmod +x full_export.sh
./full_export.sh
案例 7: Oracle坏块跳过恢复
场景:数据文件存在坏块,需要跳过坏块提取可用数据
操作步骤:
./fgodu
fgodu> datafile 1 /oradata/fgedudb/system01.dbf
fgodu> datafile 2 /oradata/fgedudb/users01.dbf
fgodu> bootstrap
fgodu> set skip_bad_blocks yes
fgodu> unload table SCOTT.EMP
# 查看坏块统计
fgodu> check datafile 2
案例 8: Oracle按数据文件导出所有表
场景:知道数据文件路径,需要导出其中所有表
字典模式(推荐):
./fgodu
fgodu> datafile 1 /oradata/fgedudb/system01.dbf
fgodu> datafile 2 /oradata/fgedudb/users01.dbf
fgodu> bootstrap
fgodu> unload tablespace USERS
暴力扫描(无字典):
./fgodu
fgodu> datafile 1 /oradata/fgedudb/users01.dbf
fgodu> set db_block_size 8192
fgodu> define table EMP (EMPNO NUMBER(4), ENAME VARCHAR2(10))
fgodu> scan all 1 EMP
fgodu> unload brute 1 EMP 12345
案例 9: Oracle DMP 格式选择与导入
场景:需要生成可被 Oracle 原生工具导入的 DMP 文件
9i 环境(使用 imp):
fgodu> set output_format dmp
fgodu> .set oracle_version 9i
fgodu> unload table SCOTT.EMP
# 导入
imp userid=fgedu/fgedu123@fgedudb file=SCOTT_EMP.dmp tables=EMP ignore=y
10g+ 环境(使用 impdp):
fgodu> set output_format dmp
fgodu> .set oracle_version 10g
fgodu> unload table SCOTT.EMP
# 导入
mkdir -p /tmp/dp_dir
sqlplus / as sysdba <<EOF
CREATE DIRECTORY dp_dir AS '/tmp/dp_dir';
GRANT READ, WRITE ON DIRECTORY dp_dir TO scott;
EOF
impdp userid=fgedu/fgedu123@fgedudb directory=dp_dir \
dumpfile=SCOTT_EMP.dmp tables=EMP
案例 10: Oracle 批量用户导出
场景:按用户批量导出所有表,生成统一导入脚本
操作步骤:
./fgodu
fgodu> bootstrap
fgodu> set output_format dmp
fgodu> set output_dir /tmp/recovery
fgodu> .set oracle_version 11g
# 批量导出(自动生成 import_all.sql)
fgodu> unload user HR
# 输出文件
ls /tmp/recovery/
# HR_EMPLOYEES.dmp import_HR_EMPLOYEES.sql
# HR_DEPARTMENTS.dmp import_HR_DEPARTMENTS.sql
# ...
# import_all.sql <- 批量导入脚本
# 一键导入所有表
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
sqlplus hr/hr@newdb @/tmp/recovery/import_all.sql
案例 11: Oracle字符集转换与兼容性测试(ZHS16GBK 源 → AL32UTF8 目标)
场景说明:
国内大量遗留 Oracle 数据库使用 ZHS16GBK 作为数据库字符集(中文 2 字节存储),在升级迁移到新库时通常要切换到 Unicode 字符集 AL32UTF8(中文 3 字节存储)。这个过程如果处理不当会出现「中文变问号 ???」「倒乱码 ëԺÇ」「VARCHAR2 长度突然不够」等典型问题。
本案例以最常见的 ZHS16GBK → AL32UTF8 跨字符集迁移为主线,演示 FGODU 如何保持源数据库的原始字节序不做任何转换,从而确保字符集转换只在 Oracle 导入阶段发生一次、可观测、可验证。案例同时覆盖:SQL INSERT / SQL*Loader / DMP (impdp) 三种输出格式,最后用 DUMP() 函数做字节级校验,确保数据 100% 一致。
准备一张含多语言测试数据的表(源库端造数,如源库已报废可跳过直接用 FGODU 读文件):
-- 源库(ZHS16GBK)建测试表并造多语言混合数据
CREATE TABLE fgodu_charset_test (
id NUMBER(5) PRIMARY KEY,
lang VARCHAR2(20),
content VARCHAR2(200 CHAR) -- 注意用 CHAR 语义!不要用默认的 BYTE
);
INSERT INTO fgodu_charset_test VALUES (1, '简体中文', '风哥数据库培训-北京中关村软件园');
INSERT INTO fgodu_charset_test VALUES (2, '繁体中文', '風哥Oracle培訓-台北內湖科技園區');
INSERT INTO fgodu_charset_test VALUES (3, '日文', '風哥 Oracle 研修 - 東京渋谷スクランブルスクエア');
INSERT INTO fgodu_charset_test VALUES (4, '韩文', '풍가 Oracle 교육 - 서울 강남구 테헤란로');
INSERT INTO fgodu_charset_test VALUES (5, '越南文', 'Đào tạo Oracle Phong Ca - Hà Nội, Cầu Giấy');
INSERT INTO fgodu_charset_test VALUES (6, '泰文', 'ฝึกอบรม Oracle ของ Feng Ge - กรุงเทพฯ สุขุมวิท');
INSERT INTO fgodu_charset_test VALUES (7, '阿拉伯文', 'تدريب أوراكل فنغ جيه - دبي مول');
INSERT INTO fgodu_charset_test VALUES (8, 'Emoji/生僻字', '𓂀古埃及象形+𠮷野家(扩展A) + 👨💻程序员Zerowidth🚀');
INSERT INTO fgodu_charset_test VALUES (9, '混合标点', '中文(全角)"引号"【括号】《书名号》──破折号…省略号€欧元£英磅');
INSERT INTO fgodu_charset_test VALUES (10, '纯ASCII', 'Hello World! 1234567890 ~!@#$%^&*()_+');
COMMIT;
Step 1. 用 FGODU 导出数据(保留源原始字节,不做任何字符集转换)
cd /tmp
export OUT_DIR=/tmp/fgodu_charset_test
mkdir -p $OUT_DIR
# ---- 关键 1:确认源字符集 ----
# FGODU 在 bootstrap 后会自动从 sys.props$ 读出 NLS_CHARACTERSET
# 对于典型国内老库,输出通常是:
# Loading charset... ZHS16GBK / AL16UTF16
./fgodu <<FGODU_EOF
datafile 1 /oradata/fgedudb/system01.dbf
datafile 2 /oradata/fgedudb/users01.dbf
bootstrap
# 校验源字符集(和 props$ 读取一致)
show db
# ---- 关键 2:输出 DMP + SQL*Loader + SQL 三种格式 ----
# (A) 用 impdp 导入的 Data Pump 格式
set output_dir $OUT_DIR
set output_format dmp
.set oracle_version 19c
unload table SCOTT.FGODU_CHARSET_TEST
# (B) 用 sqlldr 导入的 SQL*Loader 格式
set output_format sqlldr
unload table SCOTT.FGODU_CHARSET_TEST
# (C) 用 sqlplus 直接跑的 INSERT 格式
set output_format sql
unload table SCOTT.FGODU_CHARSET_TEST
quit
FGODU_EOF
此时 $OUT_DIR/ 目录应该出现三个产物:
SCOTT_FGODU_CHARSET_TEST.dmp # Data Pump 二进制(ZHS16GBK 原始字节序)
SCOTT_FGODU_CHARSET_TEST.ctl + .txt# SQL*Loader 控制文件 + 数据
SCOTT_FGODU_CHARSET_TEST.sql # INSERT 语句(ZHS16GBK 原文)
为什么不做显式字符集转换?
FGODU 始终按源库原始字节写出,这是避免"双重转换"最稳妥的做法。让 Oracle Client(sqlplus/sqlldr/impdp)通过 NLS_LANG 去做唯一一次代码页转换,是 Oracle 官方推荐的跨字符集迁移方案。
Step 2. 目标端准备(AL32UTF8)+ 正确设置 NLS_LANG
# ---- 关键 3:NLS_LANG 必须等于「源数据库字符集」!----
# 这是整个字符集转换里最容易出错的一步。很多人设成目标端 AL32UTF8,结果导致:
# 源 GBK 字节 → Client 以为是 UTF-8 → 传给 DB 再做一次转换
# = 两次转换 + 信息丢失 = 中文变问号 ??? / 西欧乱码
# 正确做法:告诉 Oracle Client "我收到的文件是 ZHS16GBK 编码"
export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
# 验证目标数据库的字符集
sqlplus sys/YourSysPass@NEWDB_AL32UTF8 as sysdba <<'EOF'
COL parameter FOR a30
COL value FOR a30
SELECT parameter, value FROM nls_database_parameters
WHERE parameter IN ('NLS_CHARACTERSET','NLS_NCHAR_CHARACTERSET','NLS_LENGTH_SEMANTICS');
-- 期望输出:
-- NLS_CHARACTERSET AL32UTF8
-- NLS_NCHAR_CHARACTERSET AL16UTF16
-- NLS_LENGTH_SEMANTICS BYTE ← 这个要注意!默认是字节语义
EOF
目标端建表(用 CHAR 语义避免 UTF-8 下中文 3 字节导致的长度不够):
-- 目标端 (AL32UTF8)
CREATE USER scott IDENTIFIED BY tiger;
GRANT CONNECT, RESOURCE, UNLIMITED TABLESPACE TO scott;
ALTER SESSION SET NLS_LENGTH_SEMANTICS=CHAR;
CREATE TABLE scott.fgodu_charset_test (
id NUMBER(5) PRIMARY KEY,
lang VARCHAR2(20),
content VARCHAR2(200) -- 因为上面设置了 NLS_LENGTH_SEMANTICS=CHAR,
-- 这里等价于 VARCHAR2(200 CHAR)
);
长度语义提示:ZHS16GBK 下 VARCHAR2(200 BYTE) 可存 100 个中文字(2 字节/字);
AL32UTF8 下同样的中文要 3 字节/字,若继续用 BYTE 语义会出现
ORA-12899: value too large for column。迁移时务必改VARCHAR2(... CHAR)。
Step 3-A. 验证 SQL INSERT 格式的字符集导入
export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
export OUT_DIR=/tmp/fgodu_charset_test
# sqlplus 连接到新库(AL32UTF8),NLS_LANG 为 ZHS16GBK,
# Oracle Net 会**精确地**做一次 GBK→UTF-8 代码页转换
sqlplus scott/tiger@NEWDB_AL32UTF8 <<EOF
SPOOL $OUT_DIR/sql_import.log
@$OUT_DIR/SCOTT_FGODU_CHARSET_TEST.sql
COMMIT;
SPOOL OFF
EOF
Step 3-B. 验证 SQL*Loader 格式的字符集导入
export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
export OUT_DIR=/tmp/fgodu_charset_test
# CTL 文件不需要改编码,只要 NLS_LANG 对即可
# sqlldr 会按 NLS_LANG 把 .txt 当作 GBK 读 → 转换后写入 UTF-8 库
cd $OUT_DIR
sqlldr scott/tiger@NEWDB_AL32UTF8 \
control=SCOTT_FGODU_CHARSET_TEST.ctl \
log=sqlldr_import.log \
bad=sqlldr_import.bad \
errors=0
# 期望:Table SCOTT.FGODU_CHARSET_TEST:
# 10 Rows successfully loaded.
# 0 Rows not loaded due to data errors.
Step 3-C. 验证 Data Pump DMP (impdp) 格式的字符集导入
export NLS_LANG="AMERICAN_AMERICA.ZHS16GBK"
export OUT_DIR=/tmp/fgodu_charset_test
# ---- 准备 Data Pump Directory ----
sqlplus sys/YourSysPass@NEWDB_AL32UTF8 as sysdba <<'EOF'
CREATE OR REPLACE DIRECTORY fgodu_dp_dir AS '/tmp/fgodu_charset_test';
GRANT READ, WRITE ON DIRECTORY fgodu_dp_dir TO scott;
EXIT
EOF
# impdp 的字符集转换逻辑:
# DMP 文件内写了 charset_id = ZHS16GBK (ID=852)
# impdp 读取 DMP 内部 charset_id + 目标 DB NLS_CHARACTERSET (AL32UTF8=873)
# Oracle 自动做 GBK → UTF-8 转换,无需依赖外部 NLS_LANG。
# (但 DMP 文件外的 impdp 命令行日志仍受 NLS_LANG 影响)
impdp scott/tiger@NEWDB_AL32UTF8 \
directory=fgodu_dp_dir \
dumpfile=SCOTT_FGODU_CHARSET_TEST.dmp \
tables=FGODU_CHARSET_TEST \
table_exists_action=append \
logfile=impdp_charset_test.log
# 完成后查看日志,不应有任何 ORA- 错误
Step 4. 字节级验证:用 DUMP() 确认字符集转换 100% 正确
字符集测试最忌讳"肉眼看像正常",因为像「ëԺÇ」这种典型的 UTF-8 被当作 Latin-1 二次解码的错,肉眼很容易误判。必须用 Oracle 内置的 DUMP(col, 1016) 输出 字符集 ID + 字节长度 + 每个字节的十六进制来严格比对:
-- 目标端 (AL32UTF8) 执行
SET LINESIZE 300 PAGESIZE 500
COL id FOR 99
COL lang FOR a12
COL bytes_utf FOR a80
COL content FOR a55 WORD_WRAPPED
SELECT id,
lang,
content,
-- 1016 = 返回字节十六进制 + 字符集 ID
-- AL32UTF8 的 charset_id = 873;每个 UTF-8 中文 = 3 字节
-- ZHS16GBK 的 charset_id = 852;每个 GBK 中文 = 2 字节
DUMP(content, 1016) AS bytes_utf
FROM scott.fgodu_charset_test
ORDER BY id;
正确结果参考(片段):
| id | lang | content | DUMP(…) |
|---|---|---|---|
| 1 | 简体中文 | 风哥数据库培训-北京中关村软件园 | Typ=1 Len=66 CharacterSet=873: e9,a3,8e,e5,93,a5,... (UTF-8 3字节中文, ID=873) |
| 2 | 繁体中文 | 風哥Oracle培訓-台北內湖科技園區 | Typ=1 Len=72 CharacterSet=873: e9,a2,a8,e5,93,a5,... |
| 3 | 日文 | 風哥 Oracle 研修 - 東京渋谷スクランブルスクエア | Typ=1 Len=75 CharacterSet=873: e9,a2,a8,e5,93,a5,e3,83,... |
| 4 | 韩文 | 풍가 Oracle 교육 - 서울 강남구 테헤란로 | Typ=1 Len=70 CharacterSet=873: ed,92,92,ea,b0,80,... |
| 8 | Emoji/生僻字 | 𓂀古埃及…👨💻程序员Zerowidth🚀 | Typ=1 Len=89 CharacterSet=873: f0,93,82,80,228,85,... (Emoji 是 4 字节 UTF-8,前缀 f0) |
| 10 | 纯ASCII | Hello World! 1234567890… | Typ=1 Len=32 CharacterSet=873: 48,65,6c,6c,6f,... (ASCII 码不变) |
Step 5. 常见字符集故障排查手册
| 症状 | 根因 | 修复方法 |
|---|---|---|
所有中文变 ??? 问号 |
NLS_LANG 被设置成 AL32UTF8,导致 Oracle Net 把 GBK 原文当 UTF-8 解析 → 无法识别的字节全部替换为 U+FFFD (?) |
export NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK 后重新导入 |
西欧字符 Ã«ÔºÇ / å°æ˜Ž |
UTF-8 字节被当作 ISO-8859-1 (Latin-1) 又套了一次 UTF-8 编码(“双重编码”) | 说明 DMP 源端文件本身已经是 UTF-8 写的了,但 DMP 头部 charset_id 被标成 852 (ZHS16GBK)。重新用 FGODU 导出。 |
| ORA-12899 value too large | VARCHAR2 使用 BYTE 语义,GBK 2 字节/汉字 → UTF-8 3 字节/汉字,同样的字符串要多 50% 空间 | 建表时加 CHAR 语义:VARCHAR2(200 CHAR);或 ALTER SESSION SET NLS_LENGTH_SEMANTICS=CHAR; 再建表 |
| 日文片假名、韩文、越南文元音符号丢失 | 源数据库字符集实际上不是 ZHS16GBK(比如是 US7ASCII,强制塞了多语言数据),或 DUMP 字节用了非标准转义 | 先用 show db 确认 FGODU 读出的 NLS_CHARACTERSET;如果确实是 US7ASCII 且库里存了多字节字符,按源实际字节用 WE8ISO8859P1 当 NLS_LANG 强制直传 |
| NVARCHAR2/NCLOB 列乱码 | NLS_NCHAR_CHARACTERSET 没选对(老库 AL16UTF16,新库也必须保持 AL16UTF16) | SELECT * FROM nls_database_parameters WHERE parameter LIKE '%NCHAR%'; 验证两端一致 |
| DMP 导入成功但 SELECT CLOB 截断 | CLOB 存储带字符集 ID 标签,impdp 时又做了额外转换 | 改用 SQL*Loader 格式直接以 CLOB 方式导入,.ctl 中声明 CHAR(10000000) |
| sqlldr 日志显示 “Multibyte char truncated” | .ctl 文件默认列长 255 字节,GBK 原文 + UTF-8 转换后 255 不够 | 在 .ctl 中给列显式长度:content CHAR(2000) NULLIF content=BLANKS |
| 阿拉伯文 / 希伯来文显示方向不对 | 不是字符集问题,是 BiDi 双向文本渲染;Oracle 存储字节本身正确,用支持 RTL 的前端工具(如 SQL Developer 设 BiDi ON)检查即可 |
最后给出一条一键字符集诊断 SQL,所有字符集相关问题都可以先用它跑一遍快速定位:
-- 字符集综合诊断 SQL(目标端执行)
COL section FOR a18
COL item FOR a40
COL val FOR a48
SELECT 'DB 字符集' AS section, 'NLS_CHARACTERSET' AS item, value AS val
FROM nls_database_parameters WHERE parameter='NLS_CHARACTERSET' UNION ALL
SELECT 'DB 字符集', 'NLS_NCHAR_CHARACTERSET', value
FROM nls_database_parameters WHERE parameter='NLS_NCHAR_CHARACTERSET' UNION ALL
SELECT '会话字符集', 'NLS_LANG (推导)', userenv('language') FROM dual UNION ALL
SELECT '会话字符集', 'LENGTH_SEMANTICS', value
FROM nls_session_parameters WHERE parameter='NLS_LENGTH_SEMANTICS' UNION ALL
SELECT '数据分布', '总行数', COUNT(*)||''
FROM scott.fgodu_charset_test UNION ALL
SELECT '数据分布', 'content 平均字节数', TO_CHAR(AVG(LENGTHB(content)),'999.00')
FROM scott.fgodu_charset_test UNION ALL
SELECT '数据分布', 'content 平均字符数', TO_CHAR(AVG(LENGTH (content)),'999.00')
FROM scott.fgodu_charset_test UNION ALL
SELECT '数据分布', '含4字节字符(Emoji/扩展汉字)行', COUNT(*)||''
FROM scott.fgodu_charset_test WHERE LENGTH(content) <> LENGTHB(content)-1;
-- 典型健康状态:
-- AL32UTF8 / AL16UTF16
-- NLS_LENGTH_SEMANTICS = CHAR
-- content 平均字节数 ≈ 字符数的 2.6 ~ 3.1 倍(中文 3B + 英文 1B 混合平均)
-- 含 4 字节字符行 = 1 (id=8)
6. 常用问题与排查
6.1 安装与构建问题
Q1: 编译报错 “GLIBC_2.34 not found”
原因:在低版本系统上编译,但链接了高版本 GLIBC
解决方案:使用 make 或 make portable 构建便携版本:
make clean
make portable
便携版通过符号版本控制,仅依赖 GLIBC_2.2.5/2.3,可在 RHEL 5+ 运行。
Q2: Windows 编译失败
解决方案:三种编译方式任选:
# 方式1: MSVC
nmake -f Makefile.win
# 方式2: MinGW
mingw32-make -f Makefile.win CC=gcc
# 方式3: Linux 交叉编译
make mingw
Q3: 检查 GLIBC 兼容性
# 检查系统 GLIBC 版本
ldd --version | head -1
# 检查二进制所需的 GLIBC 版本
readelf -V build/portable/fgodu | grep GLIBC
# 验证可运行
./build/portable/fgodu -v
6.2 数据文件问题
Q4: “Failed to add datafile: Permission denied”
原因:运行用户对数据文件无读取权限
解决方案:
# 方法1: 用 root 或 oracle 用户运行
sudo ./fgodu
# 方法2: 修改文件权限
chmod +r /oradata/fgedudb/system01.dbf
# 方法3: 修改文件属主
chown oracle:oinstall /oradata/fgedudb/*.dbf
Q5: “cannot detect block size”
原因:数据文件头损坏,无法自动检测块大小
解决方案:手动指定块大小:
fgodu> set db_block_size 8192
fgodu> datafile 1 /oradata/fgedudb/system01.dbf
Q6: “Bootstrap failed: cannot find bootstrap$”
原因:SYSTEM 表空间损坏或未添加 SYSTEM 数据文件
解决方案:
- 确认添加了 SYSTEM 表空间的数据文件
- 如果 SYSTEM 严重损坏,使用非字典模式:
fgodu> datafile 1 /oradata/fgedudb/users01.dbf
fgodu> define table EMP (EMPNO NUMBER(4), ENAME VARCHAR2(10))
fgodu> scan all 1 EMP
6.3 数据恢复问题
Q7: “dataobj#=xxx not found in blocks (stale dictionary?)”
原因:数据字典中的 dataobj# 与实际块的 dataobj# 不匹配(通常因 TRUNCATE/move 操作)
解决方案:FGODU 会自动回退到 obj# 匹配策略,提示信息会显示:
Scanning for obj#=63956/dataobj#=63956 across 5 files...
这是正常行为,FGODU 会自动处理。
Q8: 导出的数据有重复行
原因:Oracle 数据块可能包含多个行版本(UPDATE 残留)
解决方案:FGODU 已内置主键去重功能。如果仍出现重复:
- 确认表有主键
- 使用
.set oracle_version确保正确版本 - 导入后用 SQL 去重:
DELETE FROM emp WHERE rowid NOT IN (
SELECT MIN(rowid) FROM emp GROUP BY empno
);
Q9: 导出数据中文乱码
原因:字符集不匹配
解决方案:
- FGODU 自动检测数据库字符集
- 确保导入时设置正确的 NLS_LANG:
# 查看源数据库字符集
# FGODU 在导出时会显示字符集信息
# 设置环境变量(必须与源数据库一致)
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8
# 或
export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK
Q10: 导出数据包含空行/无效行
原因:DELETE/UPDATE 操作残留的无效行
解决方案:FGODU 已内置 is_empty_row 函数过滤 DELETE 残留行。如果仍有问题:
fgodu> .set oracle_version 11g
fgodu> unload table SCOTT.EMP
6.4 DMP 导入问题
Q11: ORA-39002: invalid operation
原因:使用 impdp 工具导入传统的 exp 格式 DMP 文件
解决方案:
方案1(推荐):使用正确的导入工具
# 如果 DMP 是 9i 格式,用 imp 导入
imp userid=user/pass@db file=X.dmp tables=T ignore=y
# 如果 DMP 是 10g+ 格式,用 impdp 导入
impdp userid=user/pass@db directory=DP_DIR dumpfile=X.dmp tables=T
方案2:重新生成正确格式的 DMP 文件
# 生成 9i exp/imp 格式
fgodu> .set oracle_version 9i
fgodu> set output_format dmp
fgodu> unload table SCOTT.EMP
# 然后用 imp 导入
# 或生成 10g+ expdp/impdp 格式
fgodu> .set oracle_version 10g
fgodu> unload table SCOTT.EMP
# 然后用 impdp 导入
Q12: ORA-39070: unable to open the log file
原因:impdp 找不到目录对象或无权限
解决方案:
# 1. 创建目录对象
sqlplus / as sysdba <<EOF
CREATE OR REPLACE DIRECTORY dp_dir AS '/tmp/dp_dir';
GRANT READ, WRITE ON DIRECTORY dp_dir TO scott;
EXIT
EOF
# 2. 确保目录存在且有权限
mkdir -p /tmp/dp_dir
chmod 777 /tmp/dp_dir
# 3. 重新导入
impdp userid=fgedu/fgedu123@fgedudb directory=dp_dir \
dumpfile=SCOTT_EMP.dmp tables=EMP \
logfile=import.log
Q13: impdp 报格式不兼容
原因:Oracle Data Pump 是闭源专有格式,FGODU 生成的 DMP 可能无法 100% 兼容
解决方案:使用以下替代方案之一:
方案1:使用 SQL*Loader 格式(100% 标准兼容)
fgodu> set output_format sqlldr
fgodu> unload table SCOTT.EMP
# 导入
sqlldr fgedu/fgedu123@fgedudb control=SCOTT_EMP.ctl log=import.log
方案2:使用 exp/imp 格式(10g 仍支持 imp 工具)
fgodu> .set oracle_version 9i
fgodu> set output_format dmp
fgodu> unload table SCOTT.EMP
# 用 imp 导入(10g+ 仍支持)
imp userid=fgedu/fgedu123@fgedudb file=SCOTT_EMP.dmp tables=EMP ignore=y
Q14: 导入后表结构不正确(DATE 类型加长度)
原因:旧版本生成 DDL 时对 DATE 类型错误添加长度参数
解决方案:已修复,FGODU 现在对 DATE 类型不加长度:
-- 正确的 DDL
HIRE_DATE DATE NOT NULL
-- 错误的 DDL(旧版本)
HIRE_DATE DATE(7) NOT NULL
如果仍遇到此问题,请重新编译最新版本:
make clean && make
6.5 ASM 与存储问题
Q15: “No ASM disks found”
原因:ASM 磁盘驱动未加载或路径不正确
解决方案:
# 1. 检查 oracleasm 是否加载
lsmod | grep oracleasm
# 2. 手动扫描
fgodu> asm discover /dev/oracleasm/disks
fgodu> asm discover /dev/asm-disk*
# 3. 检查磁盘权限
ls -la /dev/oracleasm/disks/
Q16: UDEV/LVM 设备无法识别
解决方案:手动指定类型:
fgodu> datafile 1 /dev/disk/by-id/scsi-xxx udev
fgodu> datafile 2 /dev/mapper/vg_oracle-lv_data lvm
6.6 性能问题
Q17: 导出速度慢
解决方案:
# 1. 增加并行度
fgodu> set parallel 8
# 或自动检测
fgodu> set parallel auto
# 2. 确认多线程已启用
fgodu> boot all # 启用并行 COL$ 扫描
Q18: 大表导出卡住
原因:可能数据量大或线程资源不足
解决方案:
# 1. 查看进度(FGODU 会实时显示)
# Scanning: [====50%====] 5000/10000 blocks
# 2. 如果线程创建失败,FGODU 会自动降级为单线程
# 3. 考虑分块导出
fgodu> scan range 1 1 10000 EMP
fgodu> scan range 1 10001 20000 EMP
6.7 Windows 特定问题
Q19: Windows 版如何指定路径?
fgodu> datafile 1 C:\oracle\oradata\system01.dbf
Q20: Windows 版支持 ASM 吗?
不支持。ASM 是 Linux 特有的存储模式,Windows 版仅支持文件系统模式。
附录
A. 字符集支持列表
| 字符集 | 说明 |
|---|---|
AL32UTF8 |
Unicode UTF-8(推荐) |
UTF8 |
Unicode UTF-8 (Oracle 旧版) |
ZHS16GBK |
简体中文 GBK |
ZHT16BIG5 |
繁体中文 BIG5 |
ZHT32EUC |
繁体中文 EUC |
WE8ISO8859P1 |
西欧 ISO-8859-1 |
WE8MSWIN1252 |
Windows-1252 |
US7ASCII |
ASCII |
JA16SJIS |
日文 Shift-JIS |
JA16EUC |
日文 EUC |
KO16KSC5601 |
韩文 KSC5601 |
B. 块大小支持
| 块大小 | 字节数 | 说明 |
|---|---|---|
| 2K | 2048 | 小型数据库 |
| 4K | 4096 | 小型数据库 |
| 8K | 8192 | 标准数据库(默认) |
| 16K | 16384 | 大型数据库 |
| 32K | 32768 | 大型数据库 |
| 64K | 65536 | 超大型数据库 |
| 128K | 131072 | 超大型数据库 |
C. 技术支持
如有问题或建议,请联系:
- 作者:风哥
| 官方网站 | http://www.fgedu.net.cn , http://www.itpux.com |
| 数据库教程 | https://edu.51cto.com/lecturer/8020378.html |
免责声明:FGODU 是一个数据恢复工具,对于生产环境,请务必先在测试环境验证,并做好数据备份。作者不对使用本工具造成的任何数据损失负责。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)