崖山数据库恢复工具FGYDU(FGEDU YashanDB DUL)
崖山数据库恢复工具FGYDU(FGEDU YashanDB DUL)
FGYDU(全称 FGEDU YashanDB DUL)是一款专门面向崖山数据库(YashanDB)的离线数据恢复与抽取工具,专门针对 YashanDB 数据文件的物理块结构进行深度解析,实现"数据库无法启动情况下的数据抢救"。
目录
一、程序介绍
1.1 工具概述
FGYDU(全称 FGEDU YashanDB DUL)是一款专门面向崖山数据库(YashanDB)的离线数据恢复与抽取工具,专门针对 YashanDB 数据文件的物理块结构进行深度解析,实现"数据库无法启动情况下的数据抢救"。
崖山数据库(YashanDB)是国产信创数据库体系的重要一员,由深圳计算科学研究院研发,已广泛应用于政务、金融、电信、能源、央企等关键行业。其数据文件采用与 Oracle 数据库高度兼容的块结构布局(包括文件头魔数、块头、ITL 事务槽、行目录、行数据区、尾校验等)。FGYDU 正是利用这种兼容性,复用成熟的 Oracle 数据块解析算法,同时针对 YashanDB 文件头特有的魔数 YASH(十六进制 0x59415348)做专有识别,实现了对 YashanDB 全系列数据文件的完美兼容解析。
1.2 工具定位
FGYDU 的核心定位是"数据库最后一道防线"。当数据库因各类故障导致无法通过常规手段(STARTUP、RMAN 恢复、EXPDP 导出、闪回)启动或读取数据时,FGYDU 提供绕过数据库实例直接读取数据文件的能力,将底层存储中的数据按物理块逐块抽取出来,导出为 DMP / SQL / CSV / TXT 等通用格式,最终在新的健康数据库中完成数据重建。
具体而言,FGYDU 适用于以下典型故障场景:
| 故障类型 | 表现形式 | 常规手段是否有效 | FGYDU 是否适用 |
|---|---|---|---|
| 控制文件全部损坏 | 数据库无法 MOUNT | 需重建控制文件 + RMAN | ✅ 直接抽取数据 |
| SYSTEM 表空间损坏 | 数据库无法 OPEN | 字典不可用,常规无效 | ✅ 暴力扫描恢复 |
| Redo 日志丢失 | 启动报 ORA-00313/00312 | 需 RMAN + 归档 | ✅ 绕过实例直接抽 |
| 数据文件介质损坏 | ORA-01157/01110 | 需 RMAN 恢复 | ✅ 跳过坏块抽取 |
| 误 DELETE 表数据 | 行数据丢失 | 需闪回或日志挖掘 | ✅ 读删除标记行 |
| 误 TRUNCATE TABLE | 表数据清空 | 需闪回或备份 | ✅ 旧段扫描恢复 |
| 误 DROP TABLE | 表与数据消失 | 需闪回回收站 | ✅ 孤儿块扫描恢复 |
| ASM 磁盘组不可挂载 | ASM 实例异常 | 需修复 ASM | ✅ 直接读 ASM 裸设备 |
| 备份失效 / 归档缺失 | RMAN 恢复中断 | 无 | ✅ 唯一兜底方案 |
1.3 工作原理
理解 FGYDU 的工作原理,需要先了解 YashanDB(与 Oracle 兼容)的数据块物理布局。以 8K 标准块为例,一个数据块在物理上由以下区域组成:
Offset (0-based) 内容 长度 (bytes)
───────────────────────────────────────────────────────────
0x0000 ────► 块头 (Block Header) ──── 20 ~ 96
├─ block type (1B): 06=DATA / 02=INDEX / 03=UNDO / 07=SEGHEAD
├─ format (1B): 块格式版本
├─ block size (2B): 本块大小 (8192 = 0x2000)
├─ relative fno (2B): 相对文件号
├─ SCN (6B): 最后一次修改 SCN
├─ checksum (2B): 块校验和
├─ corrupt flag (1B): 损坏标记
└─ ITL count (1B): 事务槽数量
0x0060 ────► ITL (Interested Transaction List) ── 24 * N
每个 ITL 槽记录 XID、UBA、LCK、FLAG、SCN 等事务信息
0x0240 ────► 表目录 (Table Directory) ──── 4 * N
0x0280 ────► 行目录 (Row Directory) ──── 2 * N
每个行目录项记录行数据的偏移与长度,flag 位含删除标记
可变偏移 ──► 行数据区 (Row Data Area)
每条行记录:[flag byte] + [column count] + [len1][data1] + ...
flag 位第 1 位 = 1 表示行已删除(DELETE 标记)
0x1FF0 ────► 尾校验 (Tail Checksum) ──── 16
───────────────────────────────────────────────────────────
Total: 8192 bytes (8K)
FGYDU 解析数据块的完整顺序为:
- 文件头检查:读取偏移 0 处的 4 字节魔数,校验是否为
0x59413348(YASH)。 - 块大小识别:读取文件头中记录的
block_size字段,自动检测 2K / 4K / 8K / 16K / 32K 五种标准块大小。 - 逐块读取:按
block_size定位到每个数据块的物理偏移,使用 64MB 大缓存批量读取(每次读 256 块),最大化 IO 吞吐。 - 块头解析:读取块类型、块校验、ITL 数量、行目录数量。
- 行目录遍历:读取每个行目录项,获取行数据在块内的偏移与长度。
- 行记录解析:按列定义(字典模式)或按 raw binary(暴力模式)反序列化每个列值。
- 尾校验校验:对每个块做 YASH 尾校验,判断是否为损坏块。
1.4 四种恢复原理总览
FGYDU 提供从"精确恢复"到"兜底抢救"的四个层次恢复能力,对应不同的故障严重程度:
① DELETE 标记位恢复
原理:行数据在块中未被物理删除,仅 flag 字节第 1 位置 1
命令:recover deleted [owner.]table
恢复率:高(只要未被覆盖可达 99%+)
② TRUNCATE 旧段扫描
原理:TRUNCATE 重置段头 HWM + 分配新 dataobj#,旧 dataobj# 对应的数据块物理上仍存在
命令:recover truncated [ts# [file# [dataobj#]]] <table>
恢复率:中高(取决于段释放后是否被重用)
③ DROP 孤儿块扫描
原理:DROP 表后字典清除,数据块变为"孤儿块"
命令:recover dropped [ts#] <table>
恢复率:中
④ 最大恢复(暴力扫描所有块)
原理:跳过字典/段头/直接扫描每个数据文件的每一个块
命令:recover max [data_dir]
恢复率:低到中(人工后处理列类型)
恢复口诀:Delete 看标记、Truncate 找旧号、Drop 扫孤儿、Max 扫全块。
版本识别机制:
datafile命令添加文件时自动输出版本号(Version 字段)。若 Version=19 表示对应 19c 内核,Version=23 对应 23c 内核。
1.5 作者信息
作者:风哥
官方网站: http://www.fgedu.net.cn , http://www.itpux.com
数据库教程: https://edu.51cto.com/lecturer/8020378.html
二、程序功能与特性
2.1 核心特性概览
FGYDU v1.0 提供 25+ 项核心恢复能力,覆盖从常规误操作到极端介质故障的各类场景。下表完整列举所有功能特性:
| # | 特性名称 | 详细说明 |
|---|---|---|
| 1 | DELETE 误删恢复 | 读取数据块中被标记为删除的行(物理仍存在),逐行还原 DELETE 操作前的数据。原理:DELETE 仅将行 flag 字节第 1 位置 1,物理字节未被擦除。 |
| 2 | TRUNCATE 误清空恢复 | 通过旧 dataobj# 扫描段重置前的数据块,恢复被 TRUNCATE 清空的表数据。原理:TRUNCATE 仅重置段头 HWM 与分配新 dataobj#,旧数据块物理未被覆写。 |
| 3 | DROP 误删除表恢复 | 扫描孤儿数据块(段已释放但未被覆写的块),无需字典即可恢复 DROP 后的表。原理:DROP 后字典清除,但物理块原封不动直到被分配给新段。 |
| 4 | 自动识别块大小 | 解析文件头自动检测 2K / 4K / 8K / 16K / 32K 五种标准块大小,无需手动配置。若自动检测失败可手动 set db_block_size 指定。 |
| 5 | 最大恢复模式 recover max | 自动发现目录下所有数据文件 + 暴力扫描所有块,兜底抢救一切可读数据。是字典完全丢失、文件号不明时的终极方案。 |
| 6 | LOB (CLOB/BLOB) 导出 | 默认支持大对象列恢复,自动识别内联存储与溢出段,超长 LOB(>1MB)独立文件保存,避免单个 SQL 文件膨胀。 |
| 7 | DMP / SQL / CSV / TXT 四种输出 | Oracle 兼容二进制 DMP(最快导入)、可执行 INSERT SQL、标准 CSV(Excel/ETL)、对齐 TXT 自由切换。 |
| 8 | 支持 15+ 操作系统 | RHEL/OEL 6-10、CentOS/Rocky/Alma、麒麟、欧拉、龙蜥、Ubuntu、Debian、SUSE、UOS、凝思磐石 + Windows 全系列。 |
| 9 | 完全静态编译单文件部署 | make static 生成零依赖可执行文件,仅需 fgydu 一个文件即可运行,可部署到 U 盘/WinPE/应急 ISO。 |
| 10 | 按 Schema / User 批量恢复 | unload user SCOTT 一键导出该用户下所有业务表数据,支持千万级表数量。 |
| 11 | 按表空间恢复 | unload tablespace USERS 或 unload tablespace 4 按表空间号/名批量导出。 |
| 12 | 按数据文件导出 | 单独扫描单个 .dbf 文件,无需控制文件或字典信息,适用于只有碎片文件的场景。 |
| 13 | 链式行(Chained Rows)修复 | recover chained 自动拼接行迁移/行链接拆分的大字段行,避免长行被切割后漏扫。 |
| 14 | 损坏块容忍与修复 | 自动跳过校验失败的块,对部分损坏的块尽可能提取可读行,最大化数据挽救率。 |
| 15 | 字典模式 + 暴力模式双引擎 | SYSTEM 可用时按段头精确扫描;字典损坏时按 dataobj# 暴力全文件扫描,双引擎自动 fallback。 |
| 16 | 多种存储类型支持 | 文件系统(file)、ASM 磁盘、裸设备(/dev/raw、/dev/sd*)、LVM/多路径(/dev/mapper)全覆盖。 |
| 17 | 块级别诊断工具 | check blocks 统计块类型分布,dump block 十六进制转储定位坏块,提供完整的块级诊断能力。 |
| 18 | 范围扫描 / 逐块定位 | scan range <file#> <start> <end> 精确定位到具体块区间扫描,比全文件扫描快 5~100 倍。 |
| 19 | 段头扫描定位孤儿段 | scan segments 遍历所有文件查找段头块,辅助字典丢失时的孤儿段定位。 |
| 20 | Tab 补全 + 历史命令 | 内置行阅读器支持 Tab 命令补全、上下箭头浏览历史命令,提升交互效率。 |
| 21 | 完整访问模式解除限制 | -all 参数 + 密码 www.fgedu.net.cn 解除每表 100 行限制,开启无限制正式恢复。 |
| 22 | 64MB IO 缓存批量读取 | 按 256 块批量 I/O(FY_UNLOAD_CHUNK),大文件扫描性能更优,充分发挥磁盘吞吐。 |
| 23 | 文件头自动识别 YashanDB 版本 | 添加文件时自动显示 DB Name、DBID、TS ID、文件大小、版本号,无需额外查询。 |
| 24 | 裸设备与 ASM 路径自动检测 | 含 /dev/raw/、/dev/mapper/、oracleasm 关键字的路径自动识别存储类型,无需手动指定。 |
| 25 | 非交互模式批量执行 | -e "command" 支持脚本化批量执行命令,便于自动化恢复流程与 nohup 后台运行。 |
2.2 性能与容量上限
| 项目 | 上限 / 配置 | 说明 |
|---|---|---|
| 最大路径长度 | 4096 | 支持超长路径 |
| 最大名称长度 | 128 | 数据库名/表名等 |
| 最大列数 | 1024 | 单表最大列数 |
| 最大数据文件数 | 4096 | 单次恢复支持的最大文件数 |
| 最大表空间数 | 256 | 远超常规库使用量 |
| 最大用户数 | 4096 | 支持大型库 |
| 最大对象数 | 65536 | 满足绝大多数生产库 |
| IO 缓存 | 64 MB | 单次批量读取 256 块(8K 块时约 2MB) |
| 默认块大小 | 8192 (8K) | YashanDB 默认配置 |
2.3 支持的块类型
FGYDU 能够识别并处理以下数据块类型:
| 块类型 | 值 | 说明 |
|---|---|---|
| DATA | 0x06 | 数据块(表行存储) |
| INDEX | 0x02 | 索引块(B-Tree 节点) |
| UNDO | 0x03 | UNDO 块(回滚数据) |
| SEGHEAD | 0x07 | 段头(Extent Map 所在) |
| EXTBITMAP | 0x08 | 区位图(段空间管理) |
| FILEHEAD | 0x12 | 文件头块 1(数据文件头) |
| FILEHEAD2 | 0x13 | 文件头块 2(备份文件头) |
| SEGHEAD_10G | 0x10 | 备用段头类型 |
2.4 支持的存储类型
| 类型 | 说明 | 示例路径 | 自动检测规则 |
|---|---|---|---|
file |
普通文件(默认) | /data/yashan/system01.dbf |
默认类型 |
asm |
ASM 磁盘 | /dev/oracleasm/disks/DATA01 |
路径含 oracleasm / asm- / asm_ |
raw |
裸设备 | /dev/raw/raw1、/dev/sdb1、/dev/nvme0n1 |
路径含 /dev/raw/ /dev/sd /dev/nvme |
lvm |
LVM / 多路径 | /dev/mapper/vg-lv_oradata |
路径含 /dev/mapper/ |
三、支持环境
3.1 Linux 系列支持
FGYDU 便携构建产物(make portable)仅需目标系统存在 GLIBC_2.2.5+,可直接拷贝到以下所有 Linux 发行版运行,无需重新编译:
| 发行版 | 支持版本 | GLIBC 要求 | 架构支持 | 备注 |
|---|---|---|---|---|
| Red Hat Enterprise Linux (RHEL) | 6 / 7 / 8 / 9 / 10 | GLIBC_2.2.5+ | x86_64 / aarch64 | 企业级首选 |
| Oracle Linux (OEL) | 6 / 7 / 8 / 9 / 10 | GLIBC_2.2.5+ | x86_64 / aarch64 | UEK 内核兼容 |
| CentOS Linux | 6 / 7 / 8 | GLIBC_2.2.5+ | x86_64 | 已 EOL 仍支持 |
| Rocky Linux | 8 / 9 | GLIBC_2.2.5+ | x86_64 / aarch64 | CentOS 替代 |
| AlmaLinux | 8 / 9 | GLIBC_2.2.5+ | x86_64 / aarch64 | CentOS 替代 |
| 中标麒麟 / 银河麒麟 (Kylin) | V7 / V10 / KV10 | GLIBC_2.2.5+ | x86_64 / aarch64 | 信创主力 |
| 欧拉 (openEuler) | 20.03 / 22.03 / 24.03 | GLIBC_2.2.5+ | x86_64 / aarch64 | 信创主力 |
| 龙蜥 (Anolis OS) | 7 / 8 | GLIBC_2.2.5+ | x86_64 / aarch64 | CentOS 兼容 |
| Ubuntu | 16.04 LTS / 18.04 / 20.04 / 22.04 / 24.04 | GLIBC_2.2.5+ | x86_64 / aarch64 | LTS 长期支持 |
| Debian | 9 / 10 / 11 / 12 | GLIBC_2.2.5+ | x86_64 / aarch64 | 稳定发行版 |
| SUSE Linux Enterprise Server (SLES) | 12 / 15 | GLIBC_2.2.5+ | x86_64 / aarch64 | 企业服务器 |
| 统信 UOS | 服务器版 / 专业版 | GLIBC_2.2.5+ | x86_64 / aarch64 | 信创桌面与服务器 |
| 凝思磐石 Linux | 4.x / 6.x / 8.x | GLIBC_2.2.5+ | x86_64 | 国产安全 OS |
| 其他基于 GLIBC 的发行版 | 内核 2.6.32+ | GLIBC_2.2.5+ | x86_64 / aarch64 | 通用兼容 |
3.2 Windows 系列支持
Windows 版本通过 MinGW-w64 或 Visual Studio 编译,生成原生 Win32 可执行文件(零依赖,不依赖 VC++ Redistributable):
| Windows 版本 | 架构 | 说明 |
|---|---|---|
| Windows 7 SP1 | x86 / x64 | 需要 KB2533623 补丁 |
| Windows 8 / 8.1 | x86 / x64 | 原生支持 |
| Windows 10 | x86 / x64 | 所有版本(1507 ~ 22H2) |
| Windows 11 | x64 / ARM64 | 所有版本(21H2 ~ 24H2) |
| Windows Server 2008 R2 SP1 | x64 | 需要 KB2533623 |
| Windows Server 2012 / 2012 R2 | x64 | 原生支持 |
| Windows Server 2016 | x64 | 原生支持 |
| Windows Server 2019 | x64 | 原生支持 |
| Windows Server 2022 | x64 | 原生支持 |
| Windows PE (WinPE) | x86 / x64 | 应急恢复环境 |
3.3 编译环境要求
| 组件 | Linux 版本要求 | Windows 版本要求 |
|---|---|---|
| 操作系统 | RHEL/OEL 6+、麒麟、欧拉、Ubuntu 等 | Windows 7 SP1+ |
| 编译器 | GCC 4.8+ 或兼容编译器 | MinGW-w64 GCC 14+ 或 Visual Studio 2015+ |
| 构建工具 | GNU Make | mingw32-make 或 VS 项目 |
| 可选依赖 | glibc-static(用于完全静态构建) | 无 |
| 内存要求 | ≥ 256 MB(编译期) | ≥ 512 MB(编译期) |
| 磁盘空间 | ≥ 50 MB(源码 + 产物) | ≥ 50 MB |
3.4 运行时资源要求
| 资源 | 最低要求 | 推荐配置 | 说明 |
|---|---|---|---|
| CPU | 单核 1 GHz | 多核 2 GHz+ | 多核加速批量扫描 |
| 内存 | 128 MB | 512 MB+ | IO 缓存 64MB + 进程开销 |
| 磁盘 | 容纳输出文件 | SSD 加速 | 输出空间 = 源数据 1.5~3 倍 |
| 文件系统 | ext3+ / NTFS+ | ext4 / xfs / NTFS | 支持大文件(>4GB) |
| 权限 | 读取数据文件 | root / dba 组 | 需读源数据文件权限 |
四、程序使用
4.1 编译与安装
4.1.1 Linux 编译
# 进入项目目录
cd /fgedu/fgedudb/FGYDU
# 安装编译依赖
# RHEL / CentOS / OEL / Rocky / AlmaLinux
yum install -y gcc gcc-c++ make glibc-static libstdc++-static
# openEuler / Kylin V10
dnf install -y gcc gcc-c++ make glibc-static
# Ubuntu / Debian
apt-get update && apt-get install -y build-essential
# 推荐:portable 便携构建(静态链接 libgcc/libstdc++,仅需 GLIBC_2.2.5+)
make portable
# 或:./build.sh portable
# 零依赖:static 完全静态构建(需先安装 glibc-static)
make static
# 或:./build.sh static
# 构建产物位置:
# build/portable/fgydu (portable, 约 2.0 MB)
# build/static/fgydu (static, 约 3.8 MB)
# 同时自动拷贝到项目根目录 ./fgydu
验证构建产物:
./fgydu -v
# FGYDU - FGEDU YashanDB DUL v1.0.0
# Running on: openEuler 22.03 (x86_64)
# Kernel: 5.10.0-60.18.0.50.oe2203.x86_64 Hostname: yashan-db01
ldd ./fgydu # portable 模式检查依赖
ldd build/static/fgydu # static → not a dynamic executable(零依赖)
4.1.2 Windows 编译
方式一:MinGW-w64 + MSYS2(推荐)
# 步骤 1:安装 MSYS2,启动 "MSYS2 MinGW 64-bit" 终端
# 步骤 2:安装工具链
pacman -Sy
pacman -S --noconfirm mingw-w64-x86_64-gcc mingw-w64-x86_64-make
# 步骤 3:编译(64 位)
cd /c/fgedudb/FGYDU
mingw32-make -f Makefile.mingw BUILD=64
# 产物:build\mingw64\fgydu.exe(约 1.9 MB,零依赖)
build\mingw64\fgydu.exe -v
方式二:Visual Studio
1) 新建空项目 (C++ Empty Project)
2) 源文件添加 src/**/*.c,头文件添加 include/**/*.h
3) 属性配置:
[C/C++] → [附加包含目录]:$(ProjectDir)..\include
[C/C++] → [预处理器定义]:WIN32;_CRT_SECURE_NO_WARNINGS;FGYDU_WIN32_BUILD
[C/C++] → [代码生成] → [运行库]:Release 选 "多线程 (/MT)"
4) Release | x64 → Ctrl+Shift+B 生成
5) 产物:x64\Release\FGYDU.exe → 重命名为 fgydu.exe
4.1.3 四种构建模式对比
| 构建模式 | 链接方式 | 文件大小 | 适用场景 | 推荐度 |
|---|---|---|---|---|
| portable | 动态 libc + 静态 libgcc/libstdc++ | ~2.0 MB | Linux 跨发行版部署 | ⭐⭐⭐⭐⭐ |
| static | 完全静态 | ~3.8 MB | 零依赖应急部署 | ⭐⭐⭐⭐ |
| debug | 动态链接 + 调试符号 | ~3.0 MB | 开发调试 | ⭐⭐⭐ |
| release | 动态链接 + -O3 优化 | ~1.5 MB | 性能测试 | ⭐⭐⭐ |
| MinGW (Win) | 完全静态 | ~1.9 MB | Windows 应急 | ⭐⭐⭐⭐⭐ |
| VS /MT (Win) | 完全静态 | ~2.1 MB | Windows 企业部署 | ⭐⭐⭐⭐ |
4.2 启动参数
FGYDU 启动语法:
fgydu [-c CONFIG] [-e COMMAND] [-v] [-h] [-all]
| 参数 | 说明 |
|---|---|
-c <config> |
指定配置 / 控制文件,启动时按文件内容执行批量命令 |
-e <command> |
执行单条命令后退出(非交互模式),支持分号分隔多条 |
-v |
显示版本与操作系统信息 |
-h |
显示帮助 |
-all |
完整访问模式(需输入密码 www.fgedu.net.cn,解除每表 100 行限制) |
启动示例:
# 显示版本与 OS 信息
./fgydu -v
# 显示帮助
./fgydu -h
# 指定配置文件
./fgydu -c control.cfg
# 执行单条命令后退出(非交互模式)
./fgydu -e "datafile 1 /data/system01.dbf"
./fgydu -e "bootstrap; unload user SCOTT"
# 完整访问模式(解除 100 行限制)
./fgydu -all
# 密码:www.fgedu.net.cn
4.3 files.txt 配置文件
FGYDU 启动时会自动加载当前工作目录下的 files.txt,批量添加数据文件。
格式:<文件号#> <路径> [file|asm|raw|lvm],以 # 开头的行为注释。
# files.txt - FGYDU 数据文件配置
# 格式: <file#> <path> [type]
1 /data/yashan/system01.dbf file
2 /data/yashan/sysaux01.dbf file
3 /data/yashan/undotbs01.dbf file
4 /data/yashan/users01.dbf file
5 /data/yashan/fgedu01.dbf file
# 裸设备 / LVM 示例
3 /dev/raw/raw1 raw
4 /dev/mapper/vg_yashan-lv_app_data lvm
6 /dev/nvme0n1p3 raw
存储类型自动检测规则:
oracleasm/asm-/asm_关键字 → ASM/dev/mapper/关键字 → LVM/dev/raw///dev/sd//dev/vd//dev/nvme→ RAW- 其他 → FILE
启动时自动加载输出示例:
Loading datafiles from files.txt...
Added datafile 1: /data/yashan/system01.dbf (file)
Loaded 5 datafiles, block size: 8192 (8K)
4.4 命令速查表
FGYDU 提供以下命令,每条命令都支持简写别名:
| 命令 | 别名 | 用途 |
|---|---|---|
datafile <#> <path> [type] |
add, a |
添加数据文件 |
bootstrap |
boot, b |
引导数据字典,加载表空间/用户/表/段/字符集 |
show db |
ls db |
显示数据库概要信息 |
show ts |
ls ts |
列出所有表空间 |
show users |
ls users |
列出所有数据库用户 |
show tables [owner] |
ls tables |
列出所有表或指定 schema 下的表 |
show cols [owner.]table |
ls cols |
查看指定表的列定义 |
describe [owner.]table |
desc |
查看表结构详情 |
unload table [owner.]table |
get table |
字典模式提取单张表数据 |
unload user <name> |
get user |
字典模式提取指定用户下所有表 |
| `unload tablespace <ts# | name>` | get ts |
unload brute <file#> <table> [dataobj#] |
get brute |
暴力模式扫描指定文件,无需字典 |
scan segments |
find segments |
扫描所有文件,输出所有段头位置 |
scan table [owner.]table |
find table |
扫描指定表(字典模式) |
scan all <file#> <table> |
find all |
暴力扫描整个数据文件 |
scan range <file#> <start> <end> <table> |
find range |
扫描指定文件的块范围 |
recover deleted [owner.]table |
rcv deleted |
恢复误 DELETE 数据 |
recover truncated [ts# [file# [dataobj#]]] <table> |
rcv truncated |
恢复误 TRUNCATE 数据 |
recover dropped [ts#] <table> |
rcv dropped |
恢复误 DROP 表 |
recover chained [owner.]table |
rcv chained |
恢复行迁移/行链接的链式行 |
recover all [file#] <table> |
rcv all |
全文件暴力扫描恢复 |
recover range [file#] [start [end]] <table> |
rcv range |
指定块范围恢复 |
recover max [data_dir] |
rcv max |
最大恢复模式:自动发现 + 全块扫描 |
check datafile <file#> |
chk datafile |
检查数据文件的块类型统计 |
check blocks <file#> |
chk blocks |
同 check datafile |
dump header <file#> <block#> |
— | 转储块头部解析结果 |
dump block <file#> <block#> |
— | 转储块头 + 前 256 字节十六进制内容 |
set db_block_size <size> |
cfg db_block_size |
手动设置块大小 |
set db_name <name> |
cfg db_name |
设置数据库名 |
| `set output_format {sql | csv | txt |
set output_dir <dir> |
cfg output_dir |
设置输出目录,默认 output |
set data_dir <dir> |
cfg data_dir |
设置数据目录(供 recover max 自动发现) |
query [owner.]table |
qry |
查询单张表的对象信息 |
query all |
qry all |
一次性列出所有表概要 |
query tablespace |
qry ts |
查询所有表空间 |
help |
? |
显示可用命令帮助 |
quit |
exit, q |
退出程序 |
4.5 标准恢复流程
从编译到首个数据恢复仅需 3 步:
第 1 步:编译 FGYDU
cd /fgedu/fgedudb/FGYDU
make portable
./fgydu -v
第 2 步:配置数据文件列表
cat > files.txt << 'EOF'
1 /data/yashan/system01.dbf file
2 /data/yashan/sysaux01.dbf file
3 /data/yashan/undotbs01.dbf file
4 /data/yashan/users01.dbf file
5 /data/yashan/fgedu01.dbf file
EOF
第 3 步:启动并执行恢复
# 建议使用完整访问模式(解除 100 行限制)
./fgydu -all
# 输入密码:www.fgedu.net.cn
# 1) 引导数据字典
fgydu> bootstrap
# Bootstrapping data dictionary...
# Loading tablespaces... 5 loaded
# Loading users... 20 loaded
# Loading tables... 158 loaded
# 2) 检查字典加载状态
fgydu> show db
fgydu> show users
# 3) 设置输出格式与目录
fgydu> set output_format sql
fgydu> set output_dir /tmp/yashan_recovery
# 4) 查看表结构 + 导出 SCOTT.EMP 表
fgydu> describe SCOTT.EMP
fgydu> unload table SCOTT.EMP
# 5) 验证导出文件 + 退出
fgydu> quit
$ ls -lh /tmp/yashan_recovery/
非交互一键执行:
./fgydu -all -e "set data_dir /data/yashan; recover max"
4.6 输出格式详解
FGYDU 支持四种输出格式,通过 set output_format 设置,默认为 DMP:
| 格式 | 优点 | 缺点 | 适用场景 | 推荐度 |
|---|---|---|---|---|
| DMP | 紧凑(比 SQL 小 ~40%),Oracle 兼容,导入最快 | 二进制不可读 | 正式大批量恢复(最快) | ⭐⭐⭐⭐⭐ |
| SQL | 可读,可编辑,可执行 | 文件大(百万行 GB 级) | 中小表,人工查看编辑 | ⭐⭐⭐⭐ |
| CSV | Excel/ETL 友好,异构迁移方便 | 大对象需特殊处理 | 业务核对、跨数据库迁移 | ⭐⭐⭐⭐ |
| TXT | 对齐美观,便于人工查看 | 不易程序处理 | 临时抽样查看 | ⭐⭐⭐ |
DMP 格式(默认):
fgydu> set output_format dmp
- 文件头标记:
YDUMP V1.0 - 导入命令:
imp USER/PSW FILE=xxx.dmp DIRECT=Y - 适用:正式大批量恢复(最快)
SQL 格式:
fgydu> set output_format sql
输出示例:
SET DEFINE OFF;
INSERT INTO SCOTT.EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO)
VALUES (7369,'SMITH','CLERK',7902,TO_DATE('1980-12-17 00:00:00','YYYY-MM-DD HH24:MI:SS'),800,NULL,20);
COMMIT;
CSV 格式:
fgydu> set output_format csv
输出示例:
EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO
7369,SMITH,CLERK,7902,1980-12-17,800,,20
TXT 格式:
fgydu> set output_format txt
输出示例:
EMPNO ENAME JOB MGR HIREDATE SAL
------ ------ ------- ----- ---------- ------
7369 SMITH CLERK 7902 1980-12-17 800
4.7 完整访问模式
为保护数据安全,FGYDU 在默认(受限)模式下,每张表最多恢复 100 行 数据。这足以验证恢复可行性,但不适合大规模恢复。
启用完整访问模式:
./fgydu -all
# Enter password for full access: ← 输入 www.fgedu.net.cn
# *** Full access mode enabled *** ← 成功
| 特性 | 受限模式(默认) | 完整访问模式(-all + 密码) |
|---|---|---|
| 每表最大行数 | 100 | 无限制 |
| 密码 | 否 | www.fgedu.net.cn |
| 用途 | 方案验证 | 正式恢复 |
⚠️ 正式恢复务必使用 -all 启动!
脚本化使用(Linux):
echo "www.fgedu.net.cn" | ./fgydu -all -e "bootstrap; unload user SCOTT"
五、程序各种案例场景与操作过程
本章给出 10 个完整案例场景,覆盖 FGYDU 的所有典型使用场景。每个案例包含:故障现象、诊断思路、完整命令序列、输出示例、验证方法。
案例 A:YashanDB数据库无法启动(最常见场景)
故障现象:YashanDB 19c 政务系统,UPS 故障后启动报错:
ORA-01113: file 1 needs media recovery
ORA-01110: data file 1: '/u02/.../system01.dbf'
ORA-01157: cannot identify/lock data file 1
控制文件大小为 0、最近备份是 2 个月前、归档缺失。RMAN 恢复不可行。
操作过程:
步骤 1:拷贝文件到恢复目录
mkdir -p /recovery/YASPRD_20260808/{original,output,scripts}
cp --sparse=always -p /u02/yashan/YASPRD/datafile/*.dbf \
/recovery/YASPRD_20260808/original/
ls -l original/*.dbf | wc -l # 校验数量
步骤 2:构建 files.txt
cd /recovery/YASPRD_20260808
cat > files.txt << 'EOF'
1 ./original/system01.dbf file
2 ./original/sysaux01.dbf file
3 ./original/undotbs01.dbf file
4 ./original/users01.dbf file
5 ./original/users02.dbf file
6 ./original/app_data01.dbf file
7 ./original/app_idx01.dbf file
8 ./original/app_lob01.dbf file
EOF
步骤 3:启动 FGYDU 并引导字典
/fgedu/fgedudb/FGYDU/fgydu -all
# 密码:www.fgedu.net.cn
fgydu> bootstrap
# Bootstrapping data dictionary...
# Loading tablespaces... 7 loaded
# Loading users... 43 loaded
# Loading tables... 1286 loaded
# Loading charset... ZHS16GBK / AL16UTF16
步骤 4:检查字典加载状态
fgydu> show db
# Database: YASPRD (DBID=2458917203)
# Tablespaces: 7 Users: 43 Tables: 1286
fgydu> show users
# USER# NAME
# 0 SYS
# 32 APP_USER
# 45 SCOTT
fgydu> show tables APP_USER # 输出 327 张业务表
步骤 5:检查数据文件块健康
fgydu> check blocks 6 # 检查 APP_DATA 文件
# Data blocks: 3,872,911 Corrupt blocks: 0 ← ✅
步骤 6:按用户导出全部数据
fgydu> set output_dir /recovery/YASPRD_20260808/output
fgydu> set output_format sql
fgydu> unload user APP_USER
# APP_USER.T_ORDER ... 2,873,412 rows
# APP_USER.T_LOG ...... 12,874,502 rows
# Total: 327 tables, 42,891,375 rows
fgydu> unload user SCOTT
fgydu> unload user HR
步骤 7:导入到新数据库
CREATE TABLESPACE APP_DATA DATAFILE '/u03/.../app_data01.dbf' SIZE 50G;
CREATE USER APP_USER IDENTIFIED BY "App@2026#Recover" DEFAULT TABLESPACE APP_DATA;
GRANT CONNECT, RESOURCE TO APP_USER;
ysql APP_USER/xxx @/recovery/.../output/APP_USER_T_ORDER.sql
验证:对比 FGYDU 日志中的行数与新库 SELECT COUNT(*) 结果,无差异即完成。
案例 B:YashanDB误 DELETE 表数据恢复
故障现象:10:15 运维执行 DELETE FROM SCOTT.EMP; COMMIT; 忘加 WHERE → 20,000 行被误删。
操作过程:
步骤 1:立刻停止应用
lsnrctl STOP # 断监听
ysql / as sysdba <<'ENDSQL'
ALTER SYSTEM ENABLE RESTRICTED SESSION;
ENDSQL
cp -p /u02/yashan/datafile/users01.dbf /recovery/users01_before_recover.dbf
步骤 2:配置 files.txt
cd /recovery
cat > files.txt << 'EOF'
1 /u02/yashan/datafile/system01.dbf file
4 /u02/yashan/datafile/users01.dbf file
EOF
/fgedu/fgedudb/FGYDU/fgydu -all
步骤 3:列出表 + 查看表结构
fgydu> bootstrap
fgydu> show tables SCOTT
# OWNER TABLE_NAME
# SCOTT EMP DEPT SALGRADE BONUS
fgydu> describe SCOTT.EMP
# Object ID: 73218 Data Object: 73218
# File/Block: 4/128 Columns: 8
# COL# NAME TYPE LENGTH
# 1 EMPNO NUMBER 22
# 2 ENAME VARCHAR2 10
步骤 4:恢复已删除数据
fgydu> set output_format csv
fgydu> set output_dir /recovery/deleted_rows
fgydu> recover deleted SCOTT.EMP
# Recovering deleted rows from SCOTT.EMP...
# Recovered 20000 deleted rows. ← ✅
步骤 5:导入到恢复表
head -n 3 /recovery/deleted_rows/SCOTT_EMP_deleted.csv
# EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO
# 7369,SMITH,CLERK,7902,1980-12-17,800,,20
# ysql 建临时表
CREATE TABLE SCOTT.EMP_RECOVERED AS SELECT * FROM SCOTT.EMP WHERE 1=0;
# SQL*Loader 导入
sqlldr SCOTT/tiger CONTROL=emp_loader.ctl DIRECT=TRUE
步骤 6:比对一致性
SELECT COUNT(*) FROM SCOTT.EMP_RECOVERED; -- 20000 ✅
INSERT INTO SCOTT.EMP SELECT * FROM SCOTT.EMP_RECOVERED;
COMMIT;
案例 C:YashanDB误 TRUNCATE 表恢复
故障现象:16:42 误 TRUNCATE TABLE HR.SALARY_HIST;,1,200,000 条历史工资记录丢失。
TRUNCATE vs DELETE 差异:
| 维度 | DELETE | TRUNCATE |
|---|---|---|
| 类型 | DML 可回滚 | DDL 不可回滚 |
| 物理 | 逐行 flag 标记 | 段头重置 HWM + 新 dataobj# |
| REDO | 量大 | 仅段头 |
恢复原理:TRUNCATE 后 dataobj# 递增(字典中旧 78512 → 新 79xxx),但旧数据块块头中的 dataobj# 字段不被逐块重写 → 用旧 78512 精准定位。
操作过程:
方式 1:自动检测模式
fgydu> bootstrap
fgydu> set output_dir /recovery/truncate_recover
fgydu> set output_format sql
fgydu> recover truncated HR.SALARY_HIST
# Auto-detection mode: searching for truncated table SALARY_HIST...
# Scanning datafile 4... found dataobj#=78512, extracting...
# Recovered 1189342 rows. ← 99.1%(10,658 行已被重用)
方式 2:精确模式(从告警日志查到 dataobj#=78512, ts#=4, file#=4)
fgydu> recover truncated 4 4 78512 HR.SALARY_HIST
# Recovering truncated table from ts#4 file#4 dataobj#78512...
# Recovered 1189342 rows. ← 速度快 10~20 倍
方式 3:暴力兜底
fgydu> scan brute 4 SALARY_HIST 78512
校验:
SELECT TO_CHAR(SUM(SALARY_AMOUNT),'FM999,999,999,990.00')
FROM HR.SALARY_HIST_RECOVERED;
-- 2,854,392,118.50 ← 与财务报表吻合 ✅
案例 D:YashanDB误 DROP TABLE 恢复
故障现象:20:03 误 DROP TABLE PURCHASE.PO_HEADER INCLUDING CONTENTS AND INDEXES PURGE;(PURGE 无回收站)。182,000 行采购订单丢失。
恢复原理:DROP → 字典删除 + 段空间位图标记为"free" → 物理块原封不动(直到被分配)。recover dropped 扫描孤儿块(dataobj# 在字典中找不到的)。
操作过程:
步骤 1:scan segments 找段头
fgydu> scan segments
# ...
# Segment header at file 6 block 48129 ← 疑似 PO_HEADER 段头
# Total: 1458
步骤 2:recover dropped 精确扫描表空间 6
fgydu> set output_dir /recovery/drop_recover
fgydu> set output_format sql
fgydu> recover dropped 6 PURCHASE.PO_HEADER
# Recovering dropped table PO_HEADER in tablespace #6...
# Found 248 matching data blocks for dataobj#=89921
# Recovered 181842 rows. ← 99.91%
步骤 3:字典丢失时的 brute-force 人工后处理
fgydu> unload brute 6 PO_HEADER_RECOVERED 89921
# 所有列按 VARCHAR2(4000) 扫出 → CSV 导出 → 用 CTAS + TO_NUMBER/TO_DATE 修正类型
案例 E:YashanDB最大恢复(数据库严重损坏)
故障现象:机房浸水 RAID5 2 块盘损坏。数据恢复公司拼出 3 个碎片:disk1.raw(256G) / disk2_partial.img(128G) / disk3.dbf(100G)。无字典、无 SYSTEM、无控制文件。目标:能救多少救多少。
操作过程:
方式 1:CLI 命令 recover max
fgydu> set output_dir /mnt/rescue/output
fgydu> set output_format csv
fgydu> recover max /mnt/rescue
# Maximum recovery mode: auto-discovering data files in /mnt/rescue...
# Auto-discovered datafile 1: /mnt/rescue/disk1.raw
# Auto-discovered datafile 2: /mnt/rescue/disk2_partial.img
# Auto-discovered datafile 3: /mnt/rescue/disk3_recovered.dbf
# Scanning ALL blocks in all datafiles...
# File 1: 472,938 rows (2,405 corrupt skipped)
# File 2: 182,301 rows (12,882 corrupt skipped)
# File 3: 539,412 rows (887 corrupt skipped)
# Maximum recovery: 1,194,651 rows recovered.
等价写法:
fgydu> set data_dir /mnt/rescue
fgydu> recover max
方式 2:逐文件 brute 精细扫描
fgydu> datafile 10 /mnt/rescue/disk3_recovered.dbf
fgydu> scan brute 10 T_FIN_GL_2024 0
# Scanned 127,492 rows
方式 3:范围扫描(坏道已知)
fgydu> datafile 20 /mnt/rescue/disk2_partial.img
fgydu> scan range 20 100000 1200000 RECOVERED_GOOD_RANGE
# Scanned 301,878 rows ← 只扫好块区间,跳过坏道
验证:
wc -l /mnt/rescue/output/RECOVERED.MAX_RECOVERY.csv
# 1194652 ← 1 表头 + 1,194,651 数据
head -n 4 /mnt/rescue/output/RECOVERED.MAX_RECOVERY.csv
# DATA
# 202351,PO20240103007,2024-01-03,85000.00,已入库 ← 业务有意义 ✅
案例 F:YashanDB按用户导出全部数据
故障现象:迁移 SCOTT 用户下所有 120 张表(总计 ~80GB),原库控制文件损坏无法启动。
操作过程:
./fgydu -all
# files.txt 已加载 system+sysaux+undotbs+users
fgydu> bootstrap
# Tables: 1286 loaded
fgydu> set output_dir /recovery/SCOTT_full
fgydu> set output_format dmp
fgydu> unload user SCOTT
输出示例:
Unloading all tables for user SCOTT...
SCOTT.T1 ... 45,210 rows
SCOTT.T2 ... 1,842 rows
SCOTT.T3 ... 209,185 rows
...
Total: 120 tables, 18,271,935 rows
输出文件结构:
ls -1 /recovery/SCOTT_full/ | head
SCOTT_T1.dmp
SCOTT_T2.dmp
SCOTT_T3.dmp
...
SCOTT_T120.dmp
du -sh /recovery/SCOTT_full/
# 78G
批量导入到新库脚本:
#!/bin/bash
# import_all_scott.sh
NEWDB="SCOTT/NewPass123#@NEWDB"
DIR="/recovery/SCOTT_full"
LOG="$DIR/import_logs"
mkdir -p "$LOG"
cd "$DIR"
total=$(ls *.dmp | wc -l); cur=0; ok=0; fail=0
for dmp in *.dmp; do
cur=$((cur+1))
tab=$(echo "$dmp" | sed 's/SCOTT_//;s/\.dmp$//')
echo "[$cur/$total] SCOTT.$tab ..."
imp "$NEWDB" FILE="$dmp" LOG="$LOG/imp_$tab.log" \
IGNORE=Y FEEDBACK=10000 BUFFER=10485760 DIRECT=Y >/dev/null 2>&1
if [ $? -eq 0 ]; then ok=$((ok+1)); echo " OK"; else
echo " FAILED"; fail=$((fail+1))
fi
done
echo "Done: OK=$ok FAILED=$fail"
案例 G:YashanDB仅单个数据文件,无字典
故障现象:外包公司只交付一个 10GB 的 users01.dbf,没有 SYSTEM、没有控制文件、没有备份。约 80~90 张业务表。
操作过程:
./fgydu -all
fgydu> datafile 1 /recovery/users_only/users01.dbf
# Added datafile 1 ... Auto-detected block size: 8192 (8K)
fgydu> bootstrap
# No SYSTEM tablespace. Bootstrap failed. ← 预期
暴力扫描:
fgydu> set output_dir /recovery/users_only/output
fgydu> set output_format csv
fgydu> scan brute 4 TEMP_TABLE 0
# Brute-force scanning datafile 4 for table TEMP_TABLE (dataobj#=0)...
# Scanned 2,487,912 rows
输出示例:
head -n 3 /recovery/users_only/output/RECOVERED_TEMP_TABLE.csv
# DATA
# 101,A001,张三,2021-05-12,15000.00,技术部,在职
# 102,A002,李四,2021-06-20,18000.00,产品部,在职
每行 7 列 → 推断为员工表:
| 位置 | 推断列名 | 推断类型 |
|---|---|---|
| 1 | EMP_ID | NUMBER(6) |
| 2 | EMP_CODE | VARCHAR2(20) |
| 3 | EMP_NAME | VARCHAR2(60) |
| 4 | HIRE_DATE | DATE |
| 5 | SALARY | NUMBER(10,2) |
| 6 | DEPT_NAME | VARCHAR2(60) |
| 7 | STATUS | VARCHAR2(10) |
后处理:人工修正列类型:
-- 第 1 步:建外部表 raw
CREATE TABLE TMP_EMP_RAW (
C1 VARCHAR2(4000), C2 VARCHAR2(4000), C3 VARCHAR2(4000),
C4 VARCHAR2(4000), C5 VARCHAR2(4000), C6 VARCHAR2(4000), C7 VARCHAR2(4000)
) ORGANIZATION EXTERNAL (
TYPE ORACLE_LOADER DEFAULT DIRECTORY DUMP_DIR
ACCESS PARAMETERS (
RECORDS DELIMITED BY NEWLINE SKIP 1
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
) LOCATION ('RECOVERED_TEMP_TABLE.csv')
);
-- 第 2 步:正式类型表
CREATE TABLE EMPLOYEE AS
SELECT
TO_NUMBER(C1) AS EMP_ID,
C2 AS EMP_CODE,
C3 AS EMP_NAME,
TO_DATE(C4, 'YYYY-MM-DD') AS HIRE_DATE,
TO_NUMBER(C5) AS SALARY,
C6 AS DEPT_NAME,
C7 AS STATUS
FROM TMP_EMP_RAW
WHERE REGEXP_LIKE(C1, '^[0-9]+$');
SELECT COUNT(*) FROM EMPLOYEE;
-- 2,487,103 ← 过滤约 809 行脏数据,有效率 99.97%
案例 H:YashanDB LOB 大对象恢复
故障现象:文档管理系统 DOCS.DOCUMENTS 表,含 CLOB(正文)+ BLOB(附件),共 42,000 行,单库 LOB 总量约 13.8GB。
CLOB/BLOB 存储格式:
| 形态 | 阈值 | 存储位置 | FGYDU 处理 |
|---|---|---|---|
| 内联 Inline | ≤ ~4000 字节 | 表段数据块行内 | 按普通列直接输出 |
| 溢出 Out-of-line | > ~4000 字节 | 独立 LOB 段(按 CHUNK 切) | 读 Locator → 拼装 Lob 段 CHUNK → 输出 |
超长 LOB(>1MB)额外独立保存到 <table>_lobs/ 目录,避免单个 SQL 膨胀。
操作过程:
fgydu> describe DOCS.DOCUMENTS
# DOCS.DOCUMENTS — 6 列:
# COL# NAME TYPE LENGTH
# 1 DOC_ID NUMBER 22
# 2 DOC_TITLE VARCHAR 200
# 3 CONTENT CLOB 4000
# 4 ATTACHMENT BLOB 4000
# 5 CREATE_USER VARCHAR 60
# 6 CREATE_TIME DATE 7
fgydu> set output_dir /recovery/docs_recover
fgydu> set output_format sql
fgydu> unload table DOCS.DOCUMENTS
输出:
Unloading DOCS.DOCUMENTS...
Extracting LOB columns... (3 inline, 41997 inline+overflow)
Unloaded 42000 rows.
CLOB exported: 42000 objects, total 1.2GB
BLOB exported: 41823 objects, total 12.6GB
Large LOBs (>1MB) saved to DOCS_DOCUMENTS_lobs/
超长 LOB 独立文件:
ls -lh /recovery/docs_recover/DOCS_DOCUMENTS_lobs/ | head -5
# -r--r--r-- 1.2M DOC_ID_1001_CONTENT.clob
# -r--r--r-- 5.8M DOC_ID_1001_ATTACHMENT.blob
# CLOB 校验:中文可读
head -n 2 DOCS_DOCUMENTS_lobs/DOC_ID_1001_CONTENT.clob
# 关于 2024 年度公司部门预算调整的通知
# 各部门:根据公司董事会 2024 年第一次会议决议...
# BLOB 校验:PDF 签名
file DOCS_DOCUMENTS_lobs/DOC_ID_1001_ATTACHMENT.blob
# PDF document, version 1.7 ← ✅
SQL 中导入恢复的 LOB:
小 LOB(SQL 内联)直接执行 FGYDU 导出的 sql 文件即可。大 LOB(独立文件)用 BFILENAME + PL/SQL 批量装载:
CREATE OR REPLACE DIRECTORY FGYDU_LOB_DIR
AS '/recovery/docs_recover/DOCS_DOCUMENTS_lobs';
GRANT READ ON DIRECTORY FGYDU_LOB_DIR TO DOCS;
DECLARE
v_clob CLOB; v_blob BLOB; v_bfile BFILE;
v_dest INTEGER := 1; v_src INTEGER := 1;
v_lang INTEGER := 0; v_warn INTEGER;
BEGIN
FOR r IN (SELECT doc_id FROM docs_documents_temp) LOOP
INSERT INTO docs.documents (doc_id, content, attachment)
VALUES (r.doc_id, EMPTY_CLOB(), EMPTY_BLOB())
RETURNING content, attachment INTO v_clob, v_blob;
v_bfile := BFILENAME('FGYDU_LOB_DIR','DOC_ID_'||r.doc_id||'_CONTENT.clob');
IF DBMS_LOB.FILEEXISTS(v_bfile)=1 THEN
DBMS_LOB.FILEOPEN(v_bfile);
DBMS_LOB.LOADCLOBFROMFILE(v_clob, v_bfile,
DBMS_LOB.GETLENGTH(v_bfile), v_dest, v_src, 871, v_lang, v_warn);
DBMS_LOB.FILECLOSE(v_bfile);
END IF;
v_bfile := BFILENAME('FGYDU_LOB_DIR','DOC_ID_'||r.doc_id||'_ATTACHMENT.blob');
IF DBMS_LOB.FILEEXISTS(v_bfile)=1 THEN
DBMS_LOB.FILEOPEN(v_bfile);
DBMS_LOB.LOADBLOBFROMFILE(v_blob, v_bfile,
DBMS_LOB.GETLENGTH(v_bfile), v_dest, v_src);
DBMS_LOB.FILECLOSE(v_bfile);
END IF;
COMMIT;
END LOOP;
END;
/
案例 I:YashanDB损坏块 / 链式行恢复
故障现象:DOCS 表空间存在磁盘坏道,部分块校验失败。
操作过程:
步骤 1:check blocks 发现 corrupt_blocks
fgydu> check blocks 8 # 文件 8 = DOCS 表空间
# Block statistics:
# Total blocks: 2,621,440 (20 GB)
# Corrupt blocks: 1,287 ← ⚠️ 磁盘坏道
步骤 2:查看一个损坏块
fgydu> dump block 8 32088
# Block #32088:
# Type: 6 (data block)
# Checksum: valid=no val=0x0000 expected=0x8AF2 ← 校验失败
# Corrupt: YES
#
# Block hex dump:
# 0000: 06 02 00 00 00 00 20 00 ...
# 0020: 00 00 00 00 00 00 00 00 ... ← 坏道零填充
步骤 3:recover chained → recover all
链式行(Row Chaining):一行超过一个块容量 → 被切 N 片分布到 N 个块。行迁移(Row Migration):UPDATE 后行膨胀超过块剩余 → 整行搬到新块。
fgydu> set output_dir /recovery/docs_recover_v2
fgydu> set output_format sql
fgydu> recover chained DOCS.DOCUMENTS
# Recovering chained rows from DOCS.DOCUMENTS...
# Found 12,482 chained/migrated row pieces
# Reassembled 12,015 complete rows
# Recovered 12015 chained rows.
fgydu> recover all 8 DOCS.DOCUMENTS
# Recovered 40,211 rows (non-corrupt blocks scanned)
dump block 查看损坏类型:
- 零填充 0x00 → 坏道清零(常见)
- 全 0xFF → 擦除未写入 / Flash 坏块
- 乱码随机字节 → 磁盘位翻转 / 校验失败
案例 J:YashanDB Windows 环境下应急恢复
故障现象:客户现场仅有 Windows 10 运维机,需紧急恢复一个 YashanDB 数据库。
操作过程:
步骤 1:在 Windows 上编译 FGYDU
# 启动 MSYS2 MinGW 64-bit 终端
cd /c/fgedudb/FGYDU
mingw32-make -f Makefile.mingw BUILD=64
# 产物:build/mingw64/fgydu.exe
cp build/mingw64/fgydu.exe ./fgydu.exe
./fgydu.exe -v
步骤 2:配置 files.txt(Windows 路径)
# files.txt — 部署在 Windows 10 运维机上
1 D:\yashan_backup\PROD_01\system01.dbf file
2 D:\yashan_backup\PROD_01\sysaux01.dbf file
3 D:\yashan_backup\PROD_01\undotbs01.dbf file
4 D:\yashan_backup\PROD_01\users01.dbf file
5 "E:\YashanDB Backup 2026-08-08\app_data.dbf" file ← 路径含空格用引号
步骤 3:启动并执行恢复
fgydu.exe -all
REM 密码:www.fgedu.net.cn
fgydu> bootstrap
fgydu> set output_dir D:\recovery\output
fgydu> set output_format sql
fgydu> unload user APP_USER
fgydu> quit
Windows 路径三种写法等价:
- 反斜杠(推荐):
D:\yashan\data\system01.dbf - 双反斜杠转义:
D:\\yashan\\data\\users01.dbf - 正斜杠:
D:/yashan/data/undotbs01.dbf
步骤 4:自动收集所有 .dbf 文件(如散落多层目录)
:: collect_dbf.bat — 自动收集 E 盘所有 .dbf 文件
@echo off
set "SRC=E:\"
set "DST=C:\recovery\all_dbf"
if not exist "%DST%" mkdir "%DST%"
dir /s /b /a-d "%SRC%*.dbf" > "%TEMP%\dbf_list.txt"
for /f "delims=" %%F in ('type "%TEMP%\dbf_list.txt"') do (
mklink /H "%DST%\%%~nxF" "%%F" >nul 2>&1
)
echo 完成!下一步:set data_dir C:\recovery\all_dbf; recover max
pause
案例汇总表
| 案例 | 场景 | 推荐命令组合 | 是否需字典 |
|---|---|---|---|
| A | 数据库无法启动 | bootstrap → show users → unload user |
是 |
| B | 误 DELETE 表数据 | recover deleted SCHEMA.TABLE |
是 |
| C | 误 TRUNCATE TABLE | recover truncated [ts# file# dataobj#] TABLE |
否 |
| D | 误 DROP TABLE | scan segments → recover dropped [ts#] TABLE |
否 |
| E | 最大恢复(磁盘坏道) | set data_dir → recover max |
否 |
| F | 按用户导出全部 Schema | unload user USERNAME |
是 |
| G | 仅单个数据文件,无字典 | scan brute <file#> TEMP 0 |
否 |
| H | LOB 大对象恢复 | describe → unload table → 校验 LOB 长度 |
是 |
| I | 损坏块 / 链式行修复 | check blocks → recover chained → recover all |
是 |
| J | Windows 环境应急恢复 | MinGW 编译 + files.txt 配置 + 标准流程 |
视情况 |
六、常用问题与排查
本章汇总 FGYDU 实际使用过程中最常见的 15 个问题及其排查方法。
Q1:块大小未识别怎么办?
现象:添加数据文件时提示 Auto-detect block size failed 或 Unknown block size。
原因:文件头损坏或非 YashanDB 数据文件。
解决:手动指定块大小,依次尝试常见值:
fgydu> set db_block_size 8192 # 先试 8K(最常见)
fgydu> datafile 1 /data/xxx.dbf
# 失败则依次尝试:16K → 4K → 32K → 2K
Q2:bootstrap 失败怎么办?
现象:bootstrap 提示 No SYSTEM tablespace 或加载字典失败。
原因:SYSTEM 表空间损坏或未添加 SYSTEM 数据文件。
解决:fallback 三步走:
- 确认 file#1 真是 SYSTEM(用
dump header 1 1看文件头类型) unload brute <file#> TEMP 0+ 人工后处理(无需字典)recover max <dir>终极兜底(无需字典、无需文件号)
Q3:CSV 中文乱码怎么办?
现象:Excel 打开 CSV 文件时中文显示为乱码。
原因:字符集不匹配(YashanDB 用 ZHS16GBK,Excel 期望 UTF-8 BOM)。
解决:
- 设置客户端字符集:
export NLS_LANG=AMERICAN_AMERICA.ZHS16GBK(或 AL32UTF8) - CSV 转 UTF-8 BOM:
iconv -f GBK -t UTF-8 file.csv > file_u8.csv,或记事本另存为 UTF-8 带 BOM - DMP/SQL 导入前确认客户端字符集匹配源库 charset(bootstrap 后会打印)
Q4:DMP 用 imp 导入报错怎么办?
现象:imp 命令导入 DMP 文件时报 invalid header 或字符集错误。
解决:最快 fallback 改用 set output_format sql,让 ysql/sqlplus 直接执行 INSERT 语句最稳:
fgydu> set output_format sql
fgydu> unload table SCOTT.EMP
Q5:恢复行数比实际少怎么办?
排查优先级:
- 是否使用 -all 完整访问模式? 忘用 → 每表只有 100 行!这是最常见原因。
- 块是否已被覆写? DELETE/TRUNCATE/DROP 后停库不够快导致物理无解。
- 试试
recover chained:大表 UPDATE 后行迁移多,普通扫描会漏。 - 试试
recover max兜底:所有精确方法无效时的终极方案。
Q6:show tables 找不到某张表怎么办?
解决:
./fgydu -e "bootstrap; query all" > all_tables.txt
grep -i PO_HEADER all_tables.txt
# 如在 recyclebin(BIN$...)→ 用 brute dataobj# 恢复
fgydu> unload brute 6 PO_HEADER 89921
Q7:permission denied 怎么办?
现象:Failed to open datafile: Permission denied
解决:
ls -l /data/system01.dbf
chmod a+r /data/system01.dbf
# raw / lvm 设备:
chown root:dba /dev/raw/raw1
chmod g+r /dev/raw/raw1
Q8:recover max 跳过 txt/log 文件怎么办?
现象:recover max 输出显示 Skipping xxx.txt / xxx.log
原因:这是预期行为,自动跳过 txt/log/conf/cfg/csv/md/sql/ctl/ini 等文本与配置文件。
解决:若数据文件后缀恰好是文本后缀,用 datafile 手动添加:
fgydu> datafile 1 /mnt/rescue/disk1.raw
Q9:Windows 路径如何写?
支持三种写法(任选一种):
- 反斜杠:
D:\yashan\system01.dbf - 双反斜杠:
D:\\yashan\\system01.dbf - 正斜杠:
D:/yashan/system01.dbf
路径含空格用英文双引号包裹:"E:\YashanDB Backup\app.dbf"
Q10:如何获取 TRUNCATE 前的旧 dataobj#?
途径:
- 告警日志(alert log):
grep -i "truncate.*SALARY_HIST" alert_*.log - 历史
describe记录或备份的 DDL 脚本 - 审计日志(如已开启对象审计)
- AWR 报告中的对象统计
- 无法获取时使用自动检测模式:
recover truncated <table>
Q11:recover max 速度太慢怎么办?
优化建议:
- 指定已知范围扫描:
scan range <file#> <start> <end> <table>比全文件快 5~100 倍 - 使用 SSD:将数据文件拷到 SSD 后扫描,速度可提升 10 倍以上
- 后台运行:
nohup ./fgydu -all -e "recover max /data" > recover.log 2>&1 & - 并行多实例:每个数据文件起一个 fgydu 实例,最后合并输出
Q12:如何校验恢复数据的完整性?
方法:
- 行数对比:FGYDU 日志中的行数与新库
SELECT COUNT(*)比对 - 汇总比对:对金额、数量等关键字段做
SUM()比对(如案例 C) - 抽样验证:业务方对核心记录抽样验证
- MD5 校验:恢复前后对源数据文件做 MD5/SHA256 校验,证明 FGYDU 未修改原件
Q13:恢复的 LOB 文件如何识别类型?
使用 file 命令:
file DOC_ID_1001_ATTACHMENT.blob
# PDF document, version 1.7
file DOC_ID_1002_ATTACHMENT.blob
# Zip archive data
file DOC_ID_1003_ATTACHMENT.blob
# PNG image data
Q14:如何生成恢复交付报告?
使用脚本化方式:
./fgydu -all 2>&1 | tee fgydu_run_$(date +%Y%m%d_%H%M%S).log
# 恢复完成后生成交付清单
{
echo "=== FGYDU 恢复交付报告 $(date) ==="
echo "源库:$SRCDB"
echo "目标输出:$OUTDIR"
echo "文件清单:"
ls -lhR "$OUTDIR"
echo "每张表行数统计:"
grep -E "rows$" fgydu_run_*.log
echo "恢复人员:$USER"
} > fgydu_delivery_report.txt
Q15:支持的操作系统 GLIBC 版本如何检查?
目标机器上执行:
ldd --version | head -1
# ldd (GNU libc) 2.17 ← 需 ≥ 2.2.5
# 检查 GLIBC_2.2.5 符号是否存在
ldd ./fgydu | grep -i "not found"
# 无输出 = 兼容 ✅
排错决策树
故障发生
│
├─ 数据库无法启动?─→ 案例A:bootstrap → unload user
│ │
│ └─ bootstrap 失败?─→ Q2:brute / recover max
│
├─ 误 DELETE?─→ 案例B:recover deleted
│ │
│ └─ 行数偏少?─→ Q5:检查 -all + recover chained
│
├─ 误 TRUNCATE?─→ 案例C:recover truncated
│ │
│ └─ 不知 dataobj#?─→ Q10:自动检测模式
│
├─ 误 DROP?─→ 案例D:scan segments → recover dropped
│
├─ 介质严重损坏?─→ 案例E:recover max
│ │
│ └─ 太慢?─→ Q11:scan range + SSD
│
├─ CSV 中文乱码?─→ Q3:iconv 转 UTF-8
│
├─ permission denied?─→ Q7:chmod a+r
│
└─ Windows 路径问题?─→ Q9:三种写法任选
七、附录
7.1 最佳实践清单
7.1.1 数据保护实践
| # | 实践 | 说明 |
|---|---|---|
| 1 | ✅ 原件只读 + 副本操作 | 原件 chmod a-w 或挂载只读 loop device;恢复一律在 cold backup 副本执行 |
| 2 | ✅ 第一时间停应用/监听 | lsnrctl stop / ALTER SYSTEM KILL SESSION / 改 DNS VIP;防止块被覆盖 |
| 3 | ✅ 禁止 reboot / restart DB | 重启触发 SMON 清理恢复区 + 空间分配,易覆写孤儿块 |
| 4 | ✅ 禁止 SHRINK / COALESCE / MOVE | 这些命令会直接压缩 HWM 下空闲空间、覆写 DELETE 标记行 |
| 5 | ✅ MD5/SHA256 校验原件 | 恢复前后比对 hash,证明 FGYDU 未修改原件 |
7.1.2 恢复顺序
① 字典模式精确恢复(优先)
bootstrap → unload table / unload user
↓ (SYSTEM 坏了 / bootstrap 失败)
② 指定 dataobj# 暴力(知道旧 dataobj# 情况下)
unload brute / recover truncated ts# file# dataobj#
↓ (连 dataobj# 也不知道)
③ 孤儿块自动扫描
scan segments → recover dropped / recover truncated auto
↓ (连字典都完全没了)
④ 逐块扫描
scan all / recover all / scan range
↓ (最后兜底)
⑤ 最大恢复
recover max
7.1.3 性能建议
| # | 建议 | 说明 |
|---|---|---|
| 1 | 大文件 DMP 输出 + imp DIRECT=Y | 速度顺序:DMP+DIRECT > CSV+SQL*Loader > SQL+INSERT |
| 2 | 256 块批量 I/O | FGYDU 内部使用 64MB 缓存 + FY_UNLOAD_CHUNK=256 块批量读取,已优化 |
| 3 | 扫描已知范围优先 scan range |
比全文件 scan brute 快 5~100 倍 |
| 4 | 大量小表用 unload user |
减少命令开销,一次性输出 |
| 5 | -e 参数脚本化 + nohup ... & |
大恢复任务后台执行 tail -f nohup.out 监控 |
7.2 目录结构
FGYDU/
├── include/ # 头文件定义
│ ├── fgydul.h # 版本、常量、块类型、返回码、输出格式枚举
│ ├── cli/cli.h # CLI 接口结构
│ ├── block/block.h # 数据块解析(文件头/块头/行目录/行数据)
│ ├── segment/segment.h # 段头解析 + 区(Extent)遍历
│ ├── dbdict/dbdict.h # 数据字典引导(表空间/用户/表/段)
│ ├── record/record.h # 行记录解析与列值反序列化
│ ├── output/output.h # DMP/SQL/CSV/TXT 四种输出写入器
│ ├── scan/scan.h # 扫描引擎 + 各类 recover 逻辑
│ ├── io/io_engine.h # IO 引擎(64MB 缓存 + 256 块批量读取)
│ ├── storage/storage.h # 存储抽象(FILE/ASM/RAW/LVM)
│ └── utils/ # 通用工具、字符串、OS 检测、内存分配
├── src/ # 实现源码(与 include 结构一一对应)
│ ├── cli/cli.c # 全部命令实现
│ ├── cli/main.c # 入口:启动参数解析、-all 密码校验、files.txt 自动加载
│ ├── block/ segment/ dbdict/ record/
│ ├── output/ scan/ io/ storage/ utils/
├── docs/
│ ├── FGYDU_MANUAL.md # 简明使用手册(v1.0 原版)
│ ├── usage_manual.md # 16 章完整案例使用手册(详细版)
│ └── README-WEB.md # 本文件(完整说明手册)
├── files.txt # 数据文件配置(启动时自动加载)
├── Makefile # 构建脚本(portable/static/debug/release/install/test/clean)
├── Makefile.mingw # Windows MinGW 构建脚本
├── build.sh # Linux 一键构建脚本
├── build.bat # Windows 一键构建脚本(MinGW / VS 自动检测)
└── fgydu # 构建产物(构建后自动拷贝到此处)
7.3 块大小对照表
| 块大小 | 字节 | 常见用途 |
|---|---|---|
| 2K | 2048 | 小型数据库 |
| 4K | 4096 | OLTP |
| 8K | 8192 | 默认(YashanDB 默认) |
| 16K | 16384 | DSS / 数据仓库 |
| 32K | 32768 | 大块数据仓库 |
7.4 联系方式
作者:风哥
官方网站: http://www.fgedu.net.cn , http://www.itpux.com
数据库教程: https://edu.51cto.com/lecturer/8020378.html

浙公网安备 33010602011771号