崖山数据库恢复工具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 解析数据块的完整顺序为:

  1. 文件头检查:读取偏移 0 处的 4 字节魔数,校验是否为 0x59413348YASH)。
  2. 块大小识别:读取文件头中记录的 block_size 字段,自动检测 2K / 4K / 8K / 16K / 32K 五种标准块大小。
  3. 逐块读取:按 block_size 定位到每个数据块的物理偏移,使用 64MB 大缓存批量读取(每次读 256 块),最大化 IO 吞吐。
  4. 块头解析:读取块类型、块校验、ITL 数量、行目录数量。
  5. 行目录遍历:读取每个行目录项,获取行数据在块内的偏移与长度。
  6. 行记录解析:按列定义(字典模式)或按 raw binary(暴力模式)反序列化每个列值。
  7. 尾校验校验:对每个块做 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 USERSunload 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 failedUnknown 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 三步走:

  1. 确认 file#1 真是 SYSTEM(用 dump header 1 1 看文件头类型)
  2. unload brute <file#> TEMP 0 + 人工后处理(无需字典)
  3. 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:恢复行数比实际少怎么办?

排查优先级

  1. 是否使用 -all 完整访问模式? 忘用 → 每表只有 100 行!这是最常见原因。
  2. 块是否已被覆写? DELETE/TRUNCATE/DROP 后停库不够快导致物理无解。
  3. 试试 recover chained:大表 UPDATE 后行迁移多,普通扫描会漏。
  4. 试试 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#?

途径

  1. 告警日志(alert log):grep -i "truncate.*SALARY_HIST" alert_*.log
  2. 历史 describe 记录或备份的 DDL 脚本
  3. 审计日志(如已开启对象审计)
  4. AWR 报告中的对象统计
  5. 无法获取时使用自动检测模式:recover truncated <table>

Q11:recover max 速度太慢怎么办?

优化建议

  1. 指定已知范围扫描scan range <file#> <start> <end> <table> 比全文件快 5~100 倍
  2. 使用 SSD:将数据文件拷到 SSD 后扫描,速度可提升 10 倍以上
  3. 后台运行nohup ./fgydu -all -e "recover max /data" > recover.log 2>&1 &
  4. 并行多实例:每个数据文件起一个 fgydu 实例,最后合并输出

Q12:如何校验恢复数据的完整性?

方法

  1. 行数对比:FGYDU 日志中的行数与新库 SELECT COUNT(*) 比对
  2. 汇总比对:对金额、数量等关键字段做 SUM() 比对(如案例 C)
  3. 抽样验证:业务方对核心记录抽样验证
  4. 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

posted @ 2026-08-30 10:30  风哥数据库教程  阅读(5)  评论(0)    收藏  举报