MySQL数据库恢复工具FGMDU(FGEDU MySQL DUL)
MySQL数据库恢复工具FGMDU(FGEDU MySQL DUL)
FGMDU(全称 FGEDU MySQL Data UnLoader)是一款由 fgedu 研发的MySQL / MariaDB / Percona 数据灾难恢复工具,当 MySQL / MariaDB / Percona Server 因损坏、误操作或系统故障无法正常启动时,FGMDU 可以直接读取 InnoDB / MyISAM 的底层存储文件,解析其页面结构与记录格式,把数据抽取为可导入的 DMP 或 SQL 文件用于恢复。
本手册为FGMDU完整说明文档,涵盖程序介绍、功能特性、使用方法、典型案例、问题排查等全部内容。
目录
- 程序介绍
- 功能特性
- 支持环境
- 程序使用
- 4.1 编译与安装
- 4.2 命令一览
- 4.3 通用选项
- 4.4 unload 命令 - 数据抽取
- 4.5 scan 命令 - 页面结构扫描
- 4.6 desc 命令 - 表结构描述
- 4.7 recover 命令 - 灾难恢复
- 4.8 坏块跳过与部分恢复
- 4.9 按用户名/数据库/对象名过滤
- 4.10 输出格式说明
- 程序各种案例场景与操作过程
- 常用问题与排查
1. 程序介绍
1.1 项目概述
FGMDU(全称 FGEDU MySQL Data UnLoader)是一款由 fgedu 研发的 MySQL 数据灾难恢复工具,当 MySQL / MariaDB / Percona Server 因损坏、误操作或系统故障无法正常启动时,FGMDU 可以直接读取 InnoDB / MyISAM 的底层存储文件,解析其页面结构与记录格式,把数据抽取为可导入的 DMP 或 SQL 文件用于恢复。
不同于依赖数据库实例在线运行的逻辑备份工具(如 mysqldump、mysqlpump),FGMDU 工作在文件系统层级,不依赖任何数据库进程。这意味着即使数据库服务彻底崩溃、ibdata1 损坏、ib_logfile 丢失、配置文件错误导致无法启动,只要底层 .ibd / .MYD / ibdata1 文件仍然可读,就有机会把数据抢救出来。
FGMDU 使用纯 C 语言编写,遵循 C99 标准,通过 src/common/portable.h 抽象层处理 Linux 与 Windows 平台差异,单一代码库即可在两个平台编译运行。工具不依赖任何第三方库(无 MySQL 客户端库、无 Boost、无 OpenSSL),仅使用标准 C 库与操作系统原生 API,因此可以静态编译后直接拷贝到目标机器运行,非常适合无网络、无包管理器的灾后恢复现场。
1.2 作者信息
- 项目名称:FGMDU(fgedu mysql dul)
- 当前版本:1.0
- 作者 / 维护方:风哥 fgedu
- 项目定位:MySQL / MariaDB / Percona 数据灾难恢复工具
- 命名含义:
- FG = fgedu(作者组织标识)
- 目标操作系统:Linux RHEL 5/6/7/8/9/10,Windows 7/8/8.1/10/11,Windows Server 2008 R2 / 2012 / 2016 / 2019 / 2022
- 支持数据库:MySQL 5.6 / 5.7 / 8.0 / 8.4 / 9.7,MariaDB 全系列,Percona Server 全系列
关于作者
| 联系方式 | 信息 |
|---|---|
| 作者 风哥 | |
| WX itpux-com | |
| QQ 113257174 | |
| 官方网站 : http://www.fgedu.net.cn , http://www.itpux.com | |
| 数据库教程 : https://edu.51cto.com/lecturer/8020378.html |
1.3 设计理念
FGMDU 在设计上遵循以下原则:
- 绕过实例,直读文件:不启动 mysqld,不连接 SQL 接口,直接以只读方式打开数据文件,避免对原始数据造成二次破坏。
- 零外部依赖:单一代码库、标准 C99、无第三方库,可静态编译后单文件部署到无网络环境。
- 跨平台一致体验:Linux 与 Windows 共享同一份源代码,命令行参数、输出格式、行为语义完全一致。
- 渐进式恢复策略:从"正常抽取"到"已删除记录恢复"再到"坏块启发式恢复"和"无字典暴力扫描",多级递进,先易后难,最大程度抢救数据。
- 安全优先:所有 I/O 操作只读,绝不修改源文件;所有内存分配带 OOM 处理;所有指针与边界检查齐全;遇到坏块自动降级而非崩溃退出。
- 详细进度反馈:抽取过程中实时输出每张表的表名、抽取行数、扫描进度,便于用户在大表恢复时监控状态。
- 命令简洁清晰:使用
unload / scan / desc / recover / version / help等完整英文单词作为主命令名,避免缩写歧义。
1.4 适用场景
FGMDU 适用于但不限于以下场景:
- 数据库无法启动:my.cnf 配置错误、ib_logfile 损坏、系统表空间崩溃、权限问题、依赖库缺失等导致 mysqld 无法启动,但数据文件完好。
- 单表损坏:某张表的
.ibd文件页面损坏,MySQL 报错无法读取该表,但其他表正常。 - 误删数据恢复:误执行
DELETE FROM删除了重要记录,被删数据仍残留在页面空闲链中尚未被覆盖。 - 误删表恢复:误执行
DROP TABLE后,在 file-per-table 模式下原.ibd文件被删除,需要先在文件系统层面恢复.ibd再用 FGMDU 抽取。 - TRUNCATE 后恢复:
TRUNCATE TABLE重建了表文件,原数据页面可能残留在旧文件中。 - 坏块磁盘恢复:存储介质出现物理坏块(EIO 错误),需要尽可能抢救坏块周围的可读数据。
- 共享主机多用户恢复:不同用户的 MySQL 数据分布在不同用户目录,需要按用户名批量恢复并交还。
- 跨平台恢复:Windows MySQL 崩溃,将
.ibd复制到 Linux 恢复服务器用 FGMDU 处理。 - 无数据字典恢复:DDL、SDI、
.frm文件全部丢失,仅有.ibd文件,使用原始暴力扫描模式提取记录字节。 - ibdata1 共享表空间恢复:使用
innodb_file_per_table=OFF模式,所有表数据在 ibdata1 中,需要按表名过滤提取。
2. 功能特性
2.1 核心功能
FGMDU 提供四大核心命令,覆盖从正常抽取到灾难恢复的完整链路:
| 命令 | 用途 | 典型场景 |
|---|---|---|
unload |
正常数据抽取 | 数据库无法启动但文件完好 |
scan |
页面结构分析 | 诊断文件损坏程度、评估恢复可行性 |
desc |
查看表结构 | 确认数据字典可用性、查看列定义 |
recover |
灾难恢复 | 文件损坏、误删数据、坏块磁盘恢复 |
功能清单:
- 从
.ibd文件(file-per-table 模式)提取数据 - 从
ibdata1(共享表空间)按表名过滤提取数据 - 从
.MYD/.MYI文件提取 MyISAM 表数据 - 恢复已删除记录(DELETE 后残留数据)
- 恢复损坏页面中的数据(FIL 头损坏时的启发式恢复)
- 恢复 BLOB / TEXT 外部页面数据
- 无数据字典情况下的原始数据暴力扫描
- 按数据库名、用户名、对象名过滤恢复
- 递归扫描整个 MySQL 数据目录
- 按数据库名自动生成子目录输出
- 支持大文件(>2GB)通过 LFS 处理
- 坏块自动跳过与部分恢复
- 详细进度与每表抽取行数报告
2.2 存储引擎支持
| 引擎 | 支持状态 | 说明 |
|---|---|---|
| InnoDB | 完全支持 | COMPACT/DYNAMIC 行格式,file-per-table 和共享表空间 |
| MyISAM | 支持 | 静态/动态行格式 |
| MEMORY | 不支持 | 数据在内存中,无持久化文件 |
| NDB Cluster | 不支持 | 分布式存储,非本地文件 |
2.3 数据字典支持
FGMDU 支持多种数据字典来源,按优先级自动尝试:
| 字典模式 | 选项值 | 说明 |
|---|---|---|
| 自动 | --dict auto |
按以下顺序依次尝试(默认) |
| InnoDB 系统字典 | --dict innodb-sys |
5.6/5.7 的 SYS_TABLES/SYS_COLUMNS |
| SDI 序列化字典 | --dict sdi |
MySQL 8.0+ 的 .sdi JSON 文件 |
| .frm 旧式字典 | --dict frm |
MySQL 5.7 及以前的 .frm 文件 |
| 无字典原始扫描 | --dict raw |
不依赖字典,暴力扫描 INDEX 页面 |
字典加载顺序(--dict auto 模式):
- 显式 DDL 文件(
--ddl指定的单表 DDL) - DDL 目录(
--ddl-dir下的<table>.sql) - SDI 目录(
--sdi-dir下的.sdiJSON) - 数据目录同位置的
.frm文件 - 数据目录同位置的
<table>.sql文件
2.4 输出格式
| 格式 | 选项值 | 说明 |
|---|---|---|
| DMP | --format dmp |
FGMDU 自定义二进制格式,每表一个 .dmp 文件(默认) |
| SQL | --format sql |
标准 SQL INSERT 语句,支持事务批量提交 |
| 两者 | --format both |
同时生成 .dmp 与 .sql |
- 输出目录结构:
- 默认(扁平):
<outdir>/<database>.<table>.dmp --struct-outdir(分层):<outdir>/<database>/<table>.dmp
- 默认(扁平):
- SQL 批量提交:默认每 1000 行
COMMIT一次,可通过--rows-per-txn调整 - 恢复输出:
recover命令输出为recovered_data.sql,包含每条记录的页号、偏移、是否已删除、可信度、原始数据十六进制
2.5 MySQL恢复能力详解
已删除记录恢复(--recover-deleted)
InnoDB 使用 COMPACT/DYNAMIC 行格式,DELETE 操作只将记录标记为已删除(设置 info_bits 的 DELETED 标志位),记录数据仍残留在页面中,直到被新数据覆盖。FGMDU 通过遍历页面记录链(包括已删除记录链)提取这些"幽灵"记录,标记为 confidence=50。
恢复条件:记录所在页面未被新数据完全覆盖、页面未被 OPTIMIZE TABLE / ALTER TABLE 重建、记录链中的 next 指针仍然可读。
损坏页面启发式恢复(--recover-corrupt)
当 InnoDB 页面的 FIL 头(前 38 字节)损坏时,正常解析会失败。FGMDU 通过搜索页面中的 infimum 和 supremum 字节标记来定位系统记录,从而重建页面结构:
- 在页面数据区域搜索
infimum字符串(7 字节 + NULL) - 在页面数据区域搜索
supremum字符串(8 字节) - 根据找到的位置推断记录链起始位置
- 尝试从残留的页面头字节中读取 heap_top、index_id 等信息
- 如果 heap_top 不可读,使用页面大小的 1/4 作为保守估计
- 遍历记录链提取所有可恢复的记录
限制:无法恢复 FIL 头和页面头同时损坏的页面;恢复的记录可能缺少部分元数据(如 index_id)。
BLOB 外部页面恢复(--blob-recovery)
InnoDB 表包含 BLOB/TEXT 大字段时,数据可能存储在外部页面(BLOB page)中。记录中只保留 20 字节的引用指针:前 4 字节为实际数据长度,后 16 字节为指向外部页面的指针(space_id + page_no + offset)。FGMDU 通过:
- 扫描记录数据,检测是否包含 BLOB 引用
- 读取引用指向的外部 BLOB 页面
- 验证页面类型为 BLOB/ZBLOB
- 提取 BLOB 页面中的数据(跳过 8 字节 BLOB 头)
- 如果数据跨越多个 BLOB 页面,沿 BLOB 链追踪
- 链追踪安全措施:最大 1000 页、循环检测
无字典暴力扫描(--raw-scan)
不依赖任何数据字典,直接扫描文件中的所有 INDEX 类型页面,提取记录的原始字节,以十六进制编码输出。适用于表结构信息完全丢失的场景,需要人工或外部脚本解析。
孤儿页面恢复
当表被 DROP 或 TRUNCATE 后,其数据页面可能仍然残留在文件中(尤其是 file-per-table 模式下的 .ibd 文件被删除前的残留)。FGMDU 的恢复扫描会尝试提取所有 INDEX 页面中的记录,无论其所属表是否仍然存在。
恢复可信度评级
| 可信度 | 含义 | 场景 |
|---|---|---|
| 100 | 正常记录 | 页面完整,记录未删除 |
| 50 | 已删除记录 | 记录被 DELETE 标记但数据仍在页面中 |
| 30 | 坏块部分恢复 | 页面有 I/O 坏块,部分数据被抢救恢复 |
2.6 稳定性与安全加固
页面解析安全检查:
- 页面大小验证:检查是否为 2 的幂且在 4K-64K 范围内
- 页面头完整性:验证 index page header 是否有足够字节读取
- heap_top 边界检查:超出页面范围时自动钳制到合理范围
- n_recs 合理性检查:记录数异常(>50000)时忽略该值
记录遍历防护:
- 循环检测:next 指针指回当前或之前的记录位置时立即停止
- 下界检查:记录偏移不能小于 PAGE_NEW_INFIMUM(94)
- 上界检查:记录偏移不能超过 heap_top + 100
- 循环计数器:最多遍历 65536 条记录后强制退出
BLOB 链追踪防护:
- 最大链长度:单条 BLOB 数据最多追踪 1000 个外部页面
- 循环检测:BLOB 链中出现页面号重复时立即停止
- 数据长度验证:BLOB 页面声明的数据长度不能超过页面大小
文件 I/O 防护与坏块处理:
- NULL 指针检查:所有 I/O 函数入口检查文件描述符和缓冲区指针
- 整数溢出检测:page_no * page_size 的乘积溢出检测
- 短读处理:partial read 时发出警告并返回错误
- 大文件支持:通过 LFS(Large File Support)支持 >2GB 文件
- 坏块自动跳过:I/O 错误时自动降级为分块读取,抢救可读数据
- 多级降级粒度:4096 → 512 → 1 字节,逐级缩小读取粒度
- 坏块统计报告:恢复完成后报告坏块页面数、部分恢复页面数和坏字节数
内存安全:
- OOM 处理:所有内存分配通过 xmalloc/xrealloc,OOM 时优雅退出
- 缓冲区初始化:页面读取前 memset 清零,防止残留数据干扰
- 资源释放:所有打开的文件描述符和分配的内存确保释放
2.7 跨平台能力
FGMDU 通过 src/common/portable.h 和 portable.c 实现跨平台抽象:
| 功能 | Linux 实现 | Windows 实现 |
|---|---|---|
| 文件打开 | open() + O_RDONLY |
_sopen_s() + _O_BINARY |
| 文件读取 | pread() |
_lseeki64() + _read() 模拟 |
| 文件状态 | stat() / fstat() |
_stati64() / _fstati64() |
| 目录遍历 | opendir() / readdir() |
_findfirst64() / _findnext64() |
| 目录创建 | mkdir(path, 0755) |
_mkdir(path) |
| 时间转换 | localtime_r() |
localtime_s() |
| 字符串比较 | strcasecmp() |
_stricmp() |
| 路径分隔符 | / |
\ 和 / 均支持 |
字节序检测不依赖 <endian.h>,有内置回退实现,确保在 RHEL 5 等旧系统上也能编译。
3. 支持环境
3.1 支持的数据库版本
| 数据库 | 支持版本 |
|---|---|
| MySQL | 5.6 / 5.7 / 8.0 / 8.4 / 9.7 |
| MariaDB | 全系列 |
| Percona Server | 全系列 |
3.2 支持的操作系统
| 平台 | 支持版本 |
|---|---|
| Linux | RHEL 5 / 6 / 7 / 8 / 9 / 10;CentOS / Oracle Linux / Rocky Linux 等兼容发行版;32 位与 64 位 |
| Windows 桌面 | 7 / 8 / 8.1 / 10 / 11 |
| Windows Server | 2008 R2 / 2012 / 2016 / 2019 / 2022 |
3.3 编译环境要求
Linux 编译环境:
- GCC 4.1+ 或 Clang 3.4+
- C99 支持
- glibc 2.5+(RHEL 5+)
- Make 或 CMake
Windows 编译环境:
- Visual Studio 2010+(VC10+)或 Build Tools 2015+
- 或 MinGW-w64(用于从 Linux 交叉编译)
- CMake 2.8+(可选)
3.4 运行环境要求
- Linux x86_64 或 x86(32 位)
- Windows x86_64(64 位)
- 足够的磁盘空间存放输出文件(建议为源数据的 2-3 倍)
- 对 MySQL 数据目录的读取权限
- 无需安装 MySQL 客户端库或任何第三方运行时
RHEL 5/6/7 兼容性说明:
- 使用
-D_POSIX_C_SOURCE=200112L确保兼容旧版 glibc O_CLOEXEC通过条件编译处理(RHEL 5 内核 2.6.18 不支持)posix_fadvise自动检测(RHEL 5 glibc 2.5 已有)__builtin_bswap*自动检测(GCC 4.1+ 支持)- 字节序检测不依赖
<endian.h>,有内置回退实现
4. FGMDU程序使用
4.1 编译与安装
FGMDU 支持在 Linux 和 Windows 两个平台上编译,使用同一份 C 源代码,通过 portable.h 抽象层处理平台差异。
方式一:Linux Makefile 编译(推荐)
# 进入项目目录
cd /path/to/FGMDU
# 直接编译
make
# 编译结果生成可执行文件 fgmdu
./fgmdu version
方式二:Linux CMake 编译
mkdir build && cd build
cmake ..
make
方式三:Windows MSVC 编译(NMAKE)
:: 1. 打开 "x64 Native Tools Command Prompt for VS"
:: 2. 进入项目目录
cd C:\path\to\FGMDU
:: 3. 使用 NMAKE 编译
nmake -f Makefile.win
:: 4. 验证
fgmdu.exe version
也可以直接双击 build_win.bat 自动检测 Visual Studio 并编译。
方式四:Windows CMake 编译
:: 使用 CMake 生成 Visual Studio 工程
mkdir build
cd build
cmake .. -G "Visual Studio 17 2022" -A x64
:: 编译
cmake --build . --config Release
方式五:从 Linux 交叉编译 Windows 版本
# 安装 MinGW-w64 工具链
# RHEL/Fedora: sudo dnf install mingw64-gcc
# Debian/Ubuntu: sudo apt install gcc-mingw-w64-x86-64
# 交叉编译
./build.sh --mingw
# 或直接: make CROSS=x86_64-w64-mingw32
# 生成的 fgmdu.exe 可直接复制到 Windows 机器运行
编译选项
Makefile 支持以下环境变量:
# 指定编译器
CC=gcc make
# 启用调试符号
CFLAGS="-g -O0" make
# 交叉编译(如 32 位 Linux)
CFLAGS="-m32" LDFLAGS="-m32" make
# 交叉编译 Windows 版本
make CROSS=x86_64-w64-mingw32
安装到系统路径
Linux:
sudo cp fgmdu /usr/local/bin/
fgmdu version
Windows:
copy fgmdu.exe C:\Windows\System32\
fgmdu.exe version
4.2 命令一览
Usage: fgmdu <command> [options]
Commands:
unload Extract table data from .ibd/.MYD files into DMP/SQL.
scan Scan an .ibd file and report page/index structure.
desc Describe a table from DDL/SDI.
recover Powerful raw recovery: scan .ibd for deleted/corrupt data.
version Print version.
help Show this help.
4.3 通用选项
以下选项适用于所有命令:
| 选项 | 说明 | 示例 |
|---|---|---|
-D, --data <path> |
数据文件或目录 | --data /var/lib/mysql |
-o, --outdir <dir> |
输出目录(默认 ./fgmdu_out) |
--outdir /tmp/recovery |
-f, --format <dmp|sql|both> |
输出格式(默认 dmp) | --format sql |
-e, --engine <innodb|myisam> |
强制指定存储引擎 | --engine innodb |
-t, --table <name> |
仅处理指定表 | --table users |
--ddl <file> |
DDL 文件(CREATE TABLE 语句) | --ddl schema.sql |
--ddl-dir <dir> |
DDL 文件目录(<table>.sql) |
--ddl-dir /backup/ddl |
--sdi-dir <dir> |
MySQL 8.0+ SDI 目录 | --sdi-dir /backup/sdi |
--ibdata <path> |
系统表空间 ibdata1 | --ibdata /var/lib/mysql/ibdata1 |
--page-size <n> |
覆盖页面大小(默认自动检测) | --page-size 8192 |
--dict <auto|innodb-sys|sdi|frm|raw> |
数据字典来源 | --dict sdi |
--rows-per-txn <n> |
SQL 批量提交行数(默认 1000) | --rows-per-txn 5000 |
--charset <name> |
字符集(默认 utf8mb4) | --charset latin1 |
--include-deleted |
包含已删除记录 | --include-deleted |
--single-file |
所有表输出到单个文件 | --single-file |
--struct-outdir |
按数据库名建子目录 | --struct-outdir |
-v, --verbose |
调试日志 | --verbose |
-q, --quiet |
静默模式 | --quiet |
4.4 unload 命令 - 数据抽取
从 InnoDB .ibd 文件或 MyISAM .MYD 文件中正常抽取数据。需要数据字典(DDL/SDI/.frm)来解析列类型。
# 从单个 .ibd 文件抽取,使用同目录的 .frm 作为字典
fgmdu unload --data /var/lib/mysql/mydb/users.ibd \
--ddl /var/lib/mysql/mydb/users.frm \
--format sql \
--outdir /tmp/recovery
# 从整个数据目录抽取所有表
fgmdu unload --data /var/lib/mysql \
--ddl-dir /backup/ddl \
--format both \
--outdir /tmp/recovery
# 指定 SDI 作为字典(MySQL 8.0+)
fgmdu unload --data /var/lib/mysql/mydb/orders.ibd \
--sdi-dir /var/lib/mysql/mydb \
--format dmp \
--outdir /tmp/recovery
# 递归扫描整个 MySQL 数据目录,按数据库自动建子目录
fgmdu unload --data /var/lib/mysql \
--ddl-dir /backup/ddl \
--format sql \
--struct-outdir \
--outdir /tmp/full_recovery
输出文件命名:
- 默认:
<outdir>/<database>.<table>.dmp或.sql --struct-outdir:<outdir>/<database>/<table>.dmp或.sql--single-file可合并为单个文件(不推荐,文件过大)
进度反馈:抽取过程中实时输出每张表的表名、页大小、文件大小、抽取行数:
[INFO] innodb '/var/lib/mysql/mydb/users.ibd': page_size=16384, size=10485760 bytes
[OK] users: 50000 rows -> /tmp/recovery
4.5 scan 命令 - 页面结构扫描
扫描 InnoDB 文件,报告页面类型分布和索引结构,用于诊断文件损坏程度。
# 扫描 .ibd 文件
fgmdu scan --data /var/lib/mysql/mydb/users.ibd
# 扫描 ibdata1
fgmdu scan --data /var/lib/mysql/ibdata1
# 指定页面大小
fgmdu scan --data /var/lib/mysql/mydb/large.ibd --page-size 32768
输出示例:
page 0: FSP_HDR
page 1: INDEX leaf index_id=1234 n_recs=500
page 2: INDEX leaf index_id=1234 n_recs=480
page 3: INDEX lvl=1 index_id=1234
page 4: BLOB
page 5: INDEX leaf index_id=1234 n_recs=510
Summary:
FSP_HDR 8: 1 pages
INDEX 17855: 50 pages
BLOB 10: 5 pages
ALLOCATED 0: 10 pages
clustered index_id=1234 (48 leaf pages)
诊断用途:
- INDEX 页面数量为 0:文件可能已损坏或被覆盖
- 大量 ALLOCATED 页面:表可能刚创建,数据量少
- BLOB 页面较多:表中包含大字段数据
- INDEX 页面 n_recs=0:可能是空页或叶子节点指针损坏
4.6 desc 命令 - 表结构描述
从 DDL 文件或 SDI 文件加载并显示表结构信息。
# 从 DDL 文件描述表结构
fgmdu desc --ddl /backup/ddl/users.sql
# 从 SDI 目录描述表结构
fgmdu desc --sdi-dir /var/lib/mysql/mydb --table users
# 从 .frm 文件描述表结构
fgmdu desc --ddl /var/lib/mysql/mydb/users.frm
输出示例:
column type len pack flags
id INT 4 4 NOT NULL
name VARCHAR 50 2 NULL
email VARCHAR 255 2 NULL
created_at DATETIME 5 5 NULL
balance DECIMAL 10 5 NULL UNSIGNED
status ENUM 1 1 NULL
4.7 recover 命令 - 灾难恢复
recover 是 FGMDU 最强大的功能,用于在以下场景恢复数据:表被 DROP 后的页面残留数据、DELETE 删除的记录(仍在页面空闲链中)、页面 FIL 头损坏的数据、无数据字典的原始数据扫描、BLOB 外部页面数据恢复。
恢复专用选项:
| 选项 | 说明 |
|---|---|
--recover-deleted |
提取已删除记录 |
--recover-corrupt |
对损坏页面执行启发式恢复 |
--recover-meta |
输出恢复元数据(页号、可信度) |
--raw-scan |
无字典模式:暴力扫描所有 INDEX 记录 |
--target-table <name> |
按表名子串过滤 |
--filter-database <db> |
按数据库名过滤 |
--filter-user <user> |
按用户名过滤(路径匹配) |
--filter-object <name> |
按对象名过滤 |
--blob-recovery |
恢复 BLOB 外部页面数据 |
--data-check <off|basic|strict> |
数据完整性检查级别(默认 basic) |
模式一:基本恢复(推荐首选)
fgmdu recover --data /var/lib/mysql/mydb/users.ibd \
--recover-deleted --recover-corrupt --recover-meta
默认启用已删除记录恢复和损坏页面恢复。输出包含每条记录的来源页号、偏移量、是否已删除和恢复可信度。
模式二:原始暴力扫描(无字典)
fgmdu recover --data /var/lib/mysql/mydb/users.ibd \
--raw-scan --recover-deleted --recover-corrupt
不需要任何数据字典,直接扫描所有 INDEX 页面,提取原始记录字节并以十六进制输出。适用于表结构信息完全丢失的场景。
模式三:完整恢复(所有选项启用)
fgmdu recover --data /var/lib/mysql/mydb/users.ibd \
--recover-deleted \
--recover-corrupt \
--recover-meta \
--blob-recovery \
--raw-scan \
--outdir /tmp/full_recovery
模式四:从整个数据目录恢复
fgmdu recover --data /var/lib/mysql \
--recover-deleted --recover-corrupt --recover-meta \
--blob-recovery
递归扫描所有子目录,自动发现 .ibd 和 ibdata1 文件。
恢复输出格式(输出为 recovered_data.sql):
-- FGMDU Recovery Output
-- Source: /var/lib/mysql/mydb/users.ibd
-- Options: deleted=yes corrupt_pages=yes raw_scan=no
-- RECORD: page=1 offset=112 deleted=0 confidence=100 len=14
INSERT INTO _recovered (page_no, rec_off, deleted, data_hex) VALUES (1, 112, 0, '5245434F52445F315F4F4B000000');
-- RECORD: page=2 offset=112 deleted=1 confidence=50 len=15
INSERT INTO _recovered (page_no, rec_off, deleted, data_hex) VALUES (2, 112, 1, '44454C455445445F5245435F310000');
4.8 MySQL坏块跳过与部分恢复
当存储介质出现物理坏块(bad block)时,读取该区域会返回 I/O 错误(EIO)。FGMDU 的坏块跳过机制可以最大程度地抢救坏块周围的可读数据,该机制自动启用,无需额外选项。
工作原理(三级递进策略):
- 正常整页读取:首先尝试一次性读取整个页面(16KB)。如果成功,正常处理。
- 分块降级读取:如果整页读取失败,按 4096 字节 → 512 字节 → 1 字节的粒度逐块重试。可读部分填入缓冲区,不可读部分用零填充。
- 启发式恢复:对部分读取的页面,尝试搜索
infimum/supremum标记来重建页面结构,提取残存的记录。
坏块统计报告:
[WARN] page 42: bad block detected (4096 bytes unreadable), attempting partial recovery (12288 bytes good)
[WARN] page 87: bad block detected (512 bytes unreadable), attempting partial recovery (15872 bytes good)
[WARN] 2 pages had bad blocks (I/O errors); 2 partially recovered (4608 bad bytes total)
[INFO] Recovery complete: 523 records from 100 pages
使用示例:
# 从有坏块的磁盘恢复数据(坏块跳过自动启用)
fgmdu recover --data /dev/sdb1 \
--recover-deleted --recover-corrupt --recover-meta \
--blob-recovery \
--outdir /tmp/recovery
# 从有坏块的 .ibd 文件恢复
fgmdu recover --data /var/lib/mysql/mydb/large_table.ibd \
--recover-deleted --recover-corrupt --recover-meta \
--outdir /tmp/recovery
最佳实践:对于严重坏块的磁盘,先用 ddrescue 创建镜像文件,再在镜像上恢复:
yum install ddrescue
ddrescue -r3 /dev/sdb1 /tmp/disk_image.img /tmp/rescue.log
fgmdu recover --data /tmp/disk_image.img --recover-deleted --recover-corrupt
4.9 MySQL按用户名/数据库/对象名过滤
FGMDU 支持按 MySQL 数据库实例的路径结构进行过滤恢复。MySQL 数据目录的典型布局:
/var/lib/mysql/ <- MySQL 数据根目录
├── ibdata1 <- 系统表空间
├── mysql/ <- 系统数据库
│ ├── user.ibd
│ └── ...
├── mydb/ <- 用户数据库 "mydb"
│ ├── users.ibd
│ ├── orders.ibd
│ └── products.ibd
├── testdb/ <- 用户数据库 "testdb"
│ └── ...
└── /home/user/mysql_data/ <- 某用户的自定义数据目录
按数据库名过滤(路径中包含 /mydb/ 段的文件才会被处理):
fgmdu recover --data /var/lib/mysql \
--filter-database mydb \
--recover-deleted --recover-corrupt --recover-meta
按用户名过滤(路径中包含 /user/ 段的文件才会被处理):
fgmdu recover --data /home \
--filter-user user \
--recover-deleted --recover-corrupt
按对象名过滤(文件名去掉扩展名后精确匹配或包含指定字符串):
fgmdu recover --data /var/lib/mysql \
--filter-object users \
--recover-deleted --recover-corrupt --recover-meta
组合过滤:
# 恢复 mydb 数据库中的 users 表
fgmdu recover --data /var/lib/mysql \
--filter-database mydb \
--filter-object users \
--recover-deleted --recover-corrupt --recover-meta --blob-recovery
过滤选项在 unload 命令中同样可用,可与 --struct-outdir 任意组合,过滤生效后仍按被命中的表所属数据库名建立子目录。
4.10 输出格式说明
DMP 格式
FGMDU 自定义的二进制导出格式,每个表一个 .dmp 文件。
文件结构:
[文件头]
- Magic: "FGMDU" (5 bytes)
- Version: 1 (2 bytes)
- Table name length + name
- Column count (2 bytes)
- Per-column metadata (type, length, name)
[数据行]
- Row length (4 bytes, big-endian)
- Row data (variable length)
- ... 重复
[文件尾]
- 0xFFFFFFFF (4 bytes, 表示结束)
SQL 格式
标准 SQL INSERT 语句,支持事务批处理。
-- FGMDU SQL Export
-- Table: mydb.users
-- Columns: 5
SET autocommit=0;
START TRANSACTION;
INSERT INTO `mydb`.`users` (`id`,`name`,`email`,`created_at`,`balance`) VALUES (1,'alice','alice@example.com','2024-01-15 10:30:00',100.50);
INSERT INTO `mydb`.`users` (`id`,`name`,`email`,`created_at`,`balance`) VALUES (2,'bob','bob@example.com','2024-01-15 11:00:00',200.00);
-- ... (每 rows_per_txn 行后)
COMMIT;
START TRANSACTION;
-- ...
COMMIT;
恢复输出格式
恢复命令输出为 SQL 文件,包含元数据注释和十六进制数据:
-- RECORD: page=1 offset=112 deleted=0 confidence=100 len=14
INSERT INTO _recovered (page_no, rec_off, deleted, data_hex)
VALUES (1, 112, 0, '5245434F52445F315F4F4B000000');
字段说明:
page_no:记录所在的 InnoDB 页号rec_off:记录在页面内的字节偏移deleted:0=存活记录,1=已删除记录confidence:恢复可信度(100=正常提取,50=已删除/损坏恢复,30=坏块页面部分恢复)data_hex:原始记录数据的十六进制编码
5. MySQL各种案例场景与操作过程
案例一:MySQL数据库无法启动,正常抽取全部数据
场景:MySQL 服务无法启动(如 my.cnf 配置错误),但数据文件完好。
# 步骤 1:确认数据文件位置
ls -la /var/lib/mysql/
# 步骤 2:准备 DDL 文件(从备份或 .frm 文件提取)
ls /backup/schema/
# 步骤 3:抽取所有数据库的所有表
fgmdu unload --data /var/lib/mysql \
--ddl-dir /backup/schema \
--format sql \
--outdir /tmp/recovery \
--rows-per-txn 5000
# 步骤 4:验证输出
ls /tmp/recovery/
# 预期:mydb.users.sql mydb.orders.sql ...
# 步骤 5:在新数据库中导入
mysql -u root -p < /tmp/recovery/mydb.users.sql
案例二:MySQL单表 .ibd 文件损坏,抽取正常页面数据
场景:某个表的 .ibd 文件部分页面损坏,MySQL 报错无法读取该表。
# 步骤 1:扫描文件查看损坏程度
fgmdu scan --data /var/lib/mysql/mydb/orders.ibd
# 步骤 2:尝试正常抽取
fgmdu unload --data /var/lib/mysql/mydb/orders.ibd \
--ddl /backup/schema/orders.sql \
--format sql \
--outdir /tmp/recovery
# 步骤 3:如果正常抽取失败,使用恢复模式
fgmdu recover --data /var/lib/mysql/mydb/orders.ibd \
--recover-corrupt --recover-meta \
--outdir /tmp/recovery
# 步骤 4:查看恢复结果
cat /tmp/recovery/recovered_data.sql
案例三:MySQL误删数据恢复(DELETE FROM)
场景:误执行 DELETE FROM users WHERE status = 'inactive',需要恢复被删除的记录。
# 立即停止 MySQL 服务,防止被删数据被覆盖
systemctl stop mysqld
# 复制 .ibd 文件到安全位置
cp /var/lib/mysql/mydb/users.ibd /tmp/users_backup.ibd
# 使用恢复模式提取已删除记录
fgmdu recover --data /tmp/users_backup.ibd \
--recover-deleted --recover-meta \
--outdir /tmp/recovery
# 查看恢复结果,deleted=1 的记录就是被删除的数据
grep "deleted=1" /tmp/recovery/recovered_data.sql
# 将十六进制数据解码为可读格式(需要根据表结构手动解析)
案例四:MySQL表被 DROP 后的恢复
场景:误执行 DROP TABLE mydb.important_table,表文件已从文件系统中删除。
# 情况 A:如果使用 file-per-table(innodb_file_per_table=ON)
# 且文件刚被删除,可能在文件系统层面恢复
# 使用 extundelete 或类似工具恢复被删除的 .ibd 文件
extundelete /dev/sda1 --restore-file var/lib/mysql/mydb/important_table.ibd
# 然后使用 FGMDU 恢复
fgmdu recover --data /tmp/restored/important_table.ibd \
--recover-deleted --recover-corrupt --recover-meta \
--blob-recovery \
--outdir /tmp/recovery
# 情况 B:如果使用共享表空间(innodb_file_per_table=OFF)
# 数据在 ibdata1 中,页面可能仍残留
fgmdu recover --data /var/lib/mysql/ibdata1 \
--target-table important_table \
--recover-deleted --recover-corrupt --recover-meta \
--outdir /tmp/recovery
案例五:MySQL从整个数据目录按数据库恢复
场景:整个 MySQL 数据目录损坏,需要按数据库分批恢复。
# 恢复 mydb 数据库的所有表
fgmdu recover --data /var/lib/mysql \
--filter-database mydb \
--recover-deleted --recover-corrupt --recover-meta \
--blob-recovery \
--outdir /tmp/recovery_mydb
# 恢复 testdb 数据库的所有表
fgmdu recover --data /var/lib/mysql \
--filter-database testdb \
--recover-deleted --recover-corrupt --recover-meta \
--blob-recovery \
--outdir /tmp/recovery_testdb
# 仅恢复特定对象
fgmdu recover --data /var/lib/mysql \
--filter-database mydb \
--filter-object users \
--recover-deleted --recover-corrupt --recover-meta \
--outdir /tmp/recovery_users
案例六:MySQL无数据字典的原始恢复
场景:数据库完全损坏,DDL、SDI、.frm 文件全部丢失,只有 .ibd 文件。
# 使用原始暴力扫描模式
fgmdu recover --data /var/lib/mysql/mydb/users.ibd \
--raw-scan --recover-deleted --recover-corrupt \
--recover-meta --blob-recovery \
--outdir /tmp/recovery
# 输出为十六进制格式,需要人工分析
# data_hex 字段包含原始记录数据
# 可以使用 Python 等工具解析十六进制数据:
python3 -c "
data = bytes.fromhex('5245434F52445F315F4F4B000000')
print(data)
# 输出: b'RECORD_1_OK\\x00\\x00\\x00'
"
案例七:MySQL MyISAM 表数据恢复
场景:MyISAM 表的 .MYD 数据文件损坏,MySQL 无法读取。
# 抽取 MyISAM 表数据
fgmdu unload --data /var/lib/mysql/mydb/logs.MYD \
--ddl /backup/schema/logs.sql \
--engine myisam \
--format sql \
--outdir /tmp/recovery
# 包含已删除记录
fgmdu unload --data /var/lib/mysql/mydb/logs.MYD \
--ddl /backup/schema/logs.sql \
--engine myisam \
--include-deleted \
--format sql \
--outdir /tmp/recovery
案例八:MySQL 8.0+ 使用 SDI 恢复
场景:MySQL 8.0+ 数据库,使用 SDI(Serialized Dictionary Information)存储表结构。
# SDI 文件通常与 .ibd 文件在同一目录
ls /var/lib/mysql/mydb/*.sdi
# 使用 SDI 作为数据字典
fgmdu unload --data /var/lib/mysql/mydb/users.ibd \
--sdi-dir /var/lib/mysql/mydb \
--format sql \
--outdir /tmp/recovery
# 或者从 SDI 描述表结构
fgmdu desc --sdi-dir /var/lib/mysql/mydb --table users
案例九:MySQL大表恢复(>2GB .ibd 文件)
场景:表数据量很大,.ibd 文件超过 2GB。
# FGMDU 支持 LFS(大文件支持),可直接处理 >2GB 文件
fgmdu unload --data /var/lib/mysql/mydb/large_table.ibd \
--ddl /backup/schema/large_table.sql \
--format sql \
--rows-per-txn 10000 \
--outdir /tmp/recovery
# 对于超大文件,建议使用 --quiet 减少日志输出
fgmdu recover --data /var/lib/mysql/mydb/huge_table.ibd \
--recover-deleted --recover-corrupt \
--quiet \
--outdir /tmp/recovery
案例十:MySQL从 ibdata1 恢复数据
场景:使用共享表空间模式(innodb_file_per_table=OFF),所有表数据存储在 ibdata1 中。
# 扫描 ibdata1 查看页面结构
fgmdu scan --data /var/lib/mysql/ibdata1
# 从 ibdata1 恢复特定表
fgmdu recover --data /var/lib/mysql/ibdata1 \
--target-table users \
--recover-deleted --recover-corrupt --recover-meta \
--outdir /tmp/recovery
# 从 ibdata1 恢复全部数据
fgmdu recover --data /var/lib/mysql/ibdata1 \
--recover-deleted --recover-corrupt --recover-meta \
--blob-recovery \
--outdir /tmp/recovery
案例十一:MySQL按用户名过滤恢复
场景:某用户将自己的 MySQL 数据目录放在 /home/alice/mysql_data/,需要仅恢复该用户的数据。
# 按用户名过滤
fgmdu recover --data /home \
--filter-user alice \
--recover-deleted --recover-corrupt --recover-meta \
--outdir /tmp/recovery_alice
# 组合过滤:alice 用户的 mydb 数据库
fgmdu recover --data /home \
--filter-user alice \
--filter-database mydb \
--recover-deleted --recover-corrupt \
--outdir /tmp/recovery_alice_mydb
案例十二:MySQL完整灾难恢复流程
场景:服务器崩溃,MySQL 完全无法启动,需要尽可能恢复所有数据。
# 步骤 1:停止 MySQL 服务,防止进一步损坏
systemctl stop mysqld
# 步骤 2:创建数据副本(永远在副本上操作)
cp -a /var/lib/mysql /tmp/mysql_backup
# 步骤 3:扫描评估损坏程度
fgmdu scan --data /tmp/mysql_backup/ibdata1
fgmdu scan --data /tmp/mysql_backup/mydb/users.ibd
# 步骤 4:尝试正常抽取(需要 DDL)
fgmdu unload --data /tmp/mysql_backup \
--ddl-dir /backup/schema \
--format both \
--outdir /tmp/recovery_normal
# 步骤 5:对无法正常抽取的表执行恢复
fgmdu recover --data /tmp/mysql_backup \
--filter-database mydb \
--recover-deleted --recover-corrupt --recover-meta \
--blob-recovery \
--outdir /tmp/recovery_mydb
fgmdu recover --data /tmp/mysql_backup \
--filter-database testdb \
--recover-deleted --recover-corrupt --recover-meta \
--blob-recovery \
--outdir /tmp/recovery_testdb
# 步骤 6:对完全无法解析的文件执行原始扫描
fgmdu recover --data /tmp/mysql_backup/corrupt_table.ibd \
--raw-scan --recover-corrupt \
--outdir /tmp/recovery_raw
# 步骤 7:验证恢复数据
ls -la /tmp/recovery_*/
wc -l /tmp/recovery_*/*.sql
# 步骤 8:在新服务器上导入恢复数据
mysql -u root -p -e "CREATE DATABASE mydb"
mysql -u root -p mydb < /tmp/recovery_normal/mydb.users.sql
案例十三:MySQL Windows 平台数据恢复
场景:MySQL 部署在 Windows 服务器上,数据库损坏无法启动,需要从 .ibd 文件恢复数据。
Windows 上的 MySQL 数据目录典型路径:
C:\ProgramData\MySQL\MySQL Server 8.0\Data\(默认安装)D:\MySQL\Data\(自定义安装)
:: 步骤 1:停止 MySQL 服务
net stop MySQL80
:: 步骤 2:复制 .ibd 文件到安全位置
copy "C:\ProgramData\MySQL\MySQL Server 8.0\Data\fgedudb\users.ibd" "D:\recovery\users.ibd"
:: 步骤 3:准备 DDL 文件(从备份获取)
:: 假设 DDL 存放在 D:\backup\schema\users.sql
:: 步骤 4:抽取数据
fgmdu.exe unload --data "D:\recovery\users.ibd" ^
--ddl "D:\backup\schema\users.sql" ^
--table users ^
--format sql ^
--outdir "D:\recovery\output"
:: 步骤 5:恢复已删除记录
fgmdu.exe recover --data "D:\recovery\users.ibd" ^
--recover-deleted --recover-meta ^
--outdir "D:\recovery\recover_output"
:: 步骤 6:从整个数据目录恢复
fgmdu.exe recover --data "C:\ProgramData\MySQL\MySQL Server 8.0\Data" ^
--filter-database mydb ^
--recover-deleted --recover-corrupt --recover-meta ^
--outdir "D:\recovery\mydb_output"
:: 步骤 7:查看恢复结果
type "D:\recovery\output\users.sql"
:: 步骤 8:导入到新数据库
mysql -u root -p -e "CREATE DATABASE mydb"
mysql -u root -p mydb < "D:\recovery\output\users.sql"
Windows 路径说明:
- FGMDU 同时支持
/和\路径分隔符 - 路径包含空格时需用双引号括起
--filter-database/--filter-user过滤器在 Windows 上同样基于路径段匹配- Windows 上的 MySQL 数据目录结构:
<DataDir>\<database>\<table>.ibd
案例十四:从 Linux 恢复 Windows MySQL 数据
场景:Windows MySQL 服务器崩溃,将数据文件复制到 Linux 恢复服务器上使用 FGMDU 恢复。
# 步骤 1:将 Windows 数据文件复制到 Linux 恢复服务器
scp admin@win-server:"/C:/ProgramData/MySQL/MySQL Server 8.0/Data/mydb/users.ibd" /tmp/recovery/
# 步骤 2:同时复制 DDL 备份
scp admin@win-server:"/D:/backup/schema/users.sql" /tmp/recovery/ddl/
# 步骤 3:在 Linux 上执行恢复
fgmdu unload --data /tmp/recovery/users.ibd \
--ddl /tmp/recovery/ddl/users.sql \
--format sql \
--outdir /tmp/recovery/output
# 步骤 4:将恢复结果传回 Windows 或直接导入 Linux MySQL
mysql -u root -p -e "CREATE DATABASE mydb"
mysql -u root -p mydb < /tmp/recovery/output/users.sql
案例十五:MySQL数据库无法启动——全库抽取并按数据库名生成子目录
场景:服务器宕机后 MySQL 无法启动(例如 ib_logfile 损坏、系统表空间崩溃、权限问题),但 .ibd / .MYD 数据文件仍然完整可读。此时无法通过 SQL 接口导出,需由 FGMDU 直接扫描整个数据目录,按数据库/用户名自动建子目录,把所有能解析的表都抽取出来。
适用条件:
- 数据库进程无法启动
- 有 DDL 备份(
--ddl-dir)、或 MySQL 8.0 的.sdi文件(--sdi-dir)、或数据目录下仍保留.frm文件 - 若以上字典都丢失,可使用
--dict raw(InnoDB 5.7 之前 .frm 丢失,依赖外部 DDL)或recover --raw-scan按无字典恢复
输出结构:
默认(向后兼容):
<outdir>/
├── db1.table1.sql
├── db1.table2.sql
└── db2.table1.sql
使用 --struct-outdir 后:
<outdir>/
├── db1/
│ ├── table1.sql
│ ├── table1.dmp
│ └── table2.sql
└── db2/
└── table1.sql
操作:
# 步骤 1:保护原始数据(在只读副本上工作!)
cp -a /var/lib/mysql /tmp/mysql_backup
ls -la /tmp/mysql_backup/
# 可以看到:mydb/ orderdb/ testdb/ mysql/ ibdata1 ...
# 步骤 2:全库 unload,按数据库名自动生成子目录
fgmdu unload --data /tmp/mysql_backup \
--ddl-dir /backup/schema \
--format both \
--struct-outdir \
--outdir /tmp/full_recovery
# 输出目录结构示例:
# /tmp/full_recovery/mydb/users.sql
# /tmp/full_recovery/mydb/users.dmp
# /tmp/full_recovery/mydb/orders.sql
# /tmp/full_recovery/orderdb/item.sql
# /tmp/full_recovery/testdb/t1.sql
# 步骤 3:若有 MySQL 8.0,优先使用 .sdi 文件获取表结构
fgmdu unload --data /tmp/mysql_backup \
--sdi-dir /tmp/mysql_backup \
--format sql \
--struct-outdir \
--outdir /tmp/full_recovery_sdi
# 步骤 4:只抽取特定数据库
fgmdu unload --data /tmp/mysql_backup \
--ddl-dir /backup/schema \
--filter-database mydb \
--struct-outdir \
--format sql \
--outdir /tmp/recovery_mydb_only
# 步骤 5:导入到新实例(按数据库逐个导入)
for db in /tmp/full_recovery/*/; do
dbname=$(basename "$db")
mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS \`$dbname\` DEFAULT CHARSET utf8mb4;"
for sql in "$db"*.sql; do
[ -f "$sql" ] && mysql -u root -p "$dbname" < "$sql"
done
done
Windows 版本:
:: 步骤 1:停止 MySQL 服务并备份
net stop MySQL80
robocopy "C:\ProgramData\MySQL\MySQL Server 8.0\Data" "D:\recovery\mysql_backup" /E /COPY:DAT
:: 步骤 2:全库抽取并按数据库名分目录
fgmdu.exe unload --data "D:\recovery\mysql_backup" ^
--ddl-dir "D:\backup\schema" ^
--format both ^
--struct-outdir ^
--outdir "D:\recovery\output"
:: 步骤 3:查看结果
dir /s /b "D:\recovery\output"
:: D:\recovery\output\fgedudb\users.sql
:: D:\recovery\output\fgedudb\users.dmp
:: D:\recovery\output\orderdb\item.sql
案例十六:MySQL按用户维度全库抽取(共享主机 / 多用户部署)
场景:共享主机上不同用户把各自 MySQL 数据放在 /home/<user>/mysql_data/、/home/<user>/data/mysql/ 等路径。数据库实例无法启动后,需要按用户名恢复,把每个用户的所有数据库/表导出到独立目录,交还给用户。
# 目录结构:
# /home/
# ├── alice/mysql_data/mydb/users.ibd
# ├── alice/mysql_data/orderdb/orders.ibd
# ├── bob/mysql_data/blogdb/posts.ibd
# └── bob/mysql_data/blogdb/comments.ibd
# 步骤 1:仅恢复 alice 用户,按数据库分子目录
fgmdu unload --data /home \
--ddl-dir /backup/schema \
--filter-user alice \
--struct-outdir \
--format sql \
--outdir /tmp/alice_recovery
# 输出(每个数据库一个子目录):
# /tmp/alice_recovery/mydb/users.sql
# /tmp/alice_recovery/orderdb/orders.sql
# 步骤 2:同时按用户 + 数据库过滤
fgmdu unload --data /home \
--ddl-dir /backup/schema \
--filter-user bob \
--filter-database blogdb \
--struct-outdir \
--format sql \
--outdir /tmp/bob_blogdb_recovery
# 输出:/tmp/bob_blogdb_recovery/blogdb/posts.sql
# /tmp/bob_blogdb_recovery/blogdb/comments.sql
# 步骤 3:一次性为所有用户导出(结合 shell 循环 + --filter-user)
for user in alice bob charlie; do
out="/tmp/all_users/${user}"
mkdir -p "$out"
fgmdu unload --data /home \
--ddl-dir /backup/schema \
--filter-user "$user" \
--struct-outdir \
--format both \
--outdir "$out"
done
# 最后得到:
# /tmp/all_users/alice/mydb/users.sql
# /tmp/all_users/alice/orderdb/orders.sql
# /tmp/all_users/bob/blogdb/posts.sql
# ...
提示:
--struct-outdir与--filter-database/--filter-user/--filter-object可以任意组合,过滤生效后,仍按被命中的表所属数据库名建立子目录。
案例十七:MySQL坏块磁盘的渐进式恢复
场景:存储磁盘出现物理坏块,dd 直接读取报 I/O 错误,MySQL 完全无法启动,需要尽可能抢救数据。
# 步骤 1:先用 ddrescue 创建镜像(跳过坏块,多次重试边缘数据)
yum install ddrescue
ddrescue -r3 /dev/sdb1 /tmp/disk_image.img /tmp/rescue.log
# 步骤 2:在镜像上扫描评估
fgmdu scan --data /tmp/disk_image.img
# 步骤 3:直接对块设备或镜像执行恢复(坏块跳过自动启用)
fgmdu recover --data /dev/sdb1 \
--recover-deleted --recover-corrupt --recover-meta \
--blob-recovery \
--outdir /tmp/recovery
# 步骤 4:检查坏块统计报告
# 关注 confidence=30 的记录,这些是从坏块页面抢救的,可能不完整
# 步骤 5:对 confidence=30 的记录人工核验
grep "confidence=30" /tmp/recovery/recovered_data.sql
6. 常用问题与排查
6.1 常见问题
Q1:提示 "page too small or NULL"
A: 文件不是有效的 InnoDB 页面文件,或文件为空。请检查文件路径和文件完整性。可用 file 命令确认文件类型,用 ls -la 确认文件大小非零。
Q2:提示 "no schema source found for table"
A: FGMDU 找不到数据字典文件。请通过以下方式之一提供:
--ddl <file>指定 DDL 文件--ddl-dir <dir>指定 DDL 文件目录--sdi-dir <dir>指定 SDI 目录(MySQL 8.0+)- 使用
--raw-scan跳过字典依赖
Q3:恢复出 0 条记录
A: 可能原因及解决方案:
- 文件不是 InnoDB 格式 - 使用
scan命令检查 - 页面全部损坏 - 尝试
--raw-scan --recover-corrupt - 数据在 ibdata1 而非 .ibd 中 - 使用
--data ibdata1路径 - 页面大小不匹配 - 使用
--page-size指定正确大小
Q4:恢复的记录数据是十六进制,如何解析?
A: 十六进制数据是原始 InnoDB 记录格式。需要根据表结构手动解析:
- 使用
desc命令获取列定义 - 根据列类型(INT、VARCHAR、DATETIME 等)从十六进制中提取字段值
- 或者编写脚本批量解码
Q5:编译时提示缺少 endian.h
A: FGMDU 自动检测系统是否支持 endian.h。如果不可用,会自动使用内置的字节序处理函数。如果编译仍然失败,请确保使用 C99 标准编译(GCC 4.1+)。
Q6:处理大文件时内存不足
A: FGMDU 一次只读取一个页面(16KB),内存占用很低。如果仍然 OOM:
- 使用
--quiet减少日志缓冲 - 检查系统可用内存
- 确认文件没有损坏导致异常分配
Q7:磁盘有坏块,恢复时遇到 I/O 错误怎么办?
A: FGMDU 自动处理坏块,无需额外选项。遇到 I/O 错误时:
- 自动降级为分块读取(4096 → 512 → 1 字节)
- 可读部分填入缓冲区,不可读部分用零填充
- 对部分读取的页面尝试启发式恢复
- 坏块页面恢复的记录标记为
confidence=30 - 恢复完成后报告坏块统计信息
如果坏块非常严重,建议先用 ddrescue 创建镜像:
ddrescue -r3 /dev/sdb1 /tmp/disk_image.img /tmp/rescue.log
fgmdu recover --data /tmp/disk_image.img --recover-deleted --recover-corrupt
Q8:如何恢复 TRUNCATE TABLE 后的数据?
A: TRUNCATE 会重建表文件,原数据页面可能被覆盖。如果使用 file-per-table 模式:
- 原
.ibd文件已被新文件替换 - 需要在文件系统层面恢复被删除的旧
.ibd文件 - 使用
extundelete或testdisk等工具恢复 - 然后使用 FGMDU 的
recover命令提取数据
Q9:Windows 路径包含空格无法识别?
A: 在 Windows 命令行中,路径包含空格时必须用双引号括起,例如:
fgmdu.exe unload --data "D:\My Data\users.ibd" --outdir "D:\Recovery Output"
FGMDU 同时支持 / 和 \ 路径分隔符,可混合使用。
Q10:如何在 Windows 上从命令行停止 MySQL 服务?
A: 使用 net stop 命令:
net stop MySQL80
:: 或
net stop MySQL57
:: 服务名取决于安装版本
Q11:scan 命令显示 INDEX 页面为 0 但文件大小正常?
A: 可能原因:
- 文件是 MyISAM 的
.MYD而非 InnoDB 的.ibd,scan 只支持 InnoDB - 页面大小不匹配,尝试
--page-size 4096或--page-size 32768 - 文件头部已损坏,FIL 头无法识别
Q12:recover 命令默认就启用了哪些选项?
A: 如果没有显式指定 --recover-deleted 或 --recover-corrupt,recover 命令会自动默认启用这两个选项(安全优先)。如需禁用,请显式指定其他选项组合。--raw-scan 在没有 DDL 时也会自动启用。
6.2 日志级别
- INFO:正常进度信息
- WARN:警告,可能影响部分输出
- ERROR:错误,可能导致恢复失败
- DEBUG:调试信息(使用
-v启用)
6.3 最佳实践
- 永远在副本上操作:不要直接操作原始数据文件,先
cp -a创建副本 - 先扫描后恢复:使用
scan命令评估损坏程度,制定恢复策略 - 先正常后恢复:先尝试
unload,失败后再用recover,从易到难递进 - 保留恢复元数据:使用
--recover-meta记录数据来源(页号、可信度) - 分批恢复:使用过滤选项分数据库/表恢复,避免一次性处理过多数据
- 验证数据:恢复后务必检查数据的完整性和正确性,特别是
confidence=30的记录 - 坏块先镜像:对于物理坏块磁盘,先用
ddrescue创建镜像再操作 - 大文件用 LFS:FGMDU 默认支持 LFS,可直接处理 >2GB 文件,无需特殊处理
关于作者
| 联系方式 | 信息 |
|---|---|
| 作者 风哥 | |
| WX itpux-com | |
| QQ 113257174 | |
| 官方网站 : http://www.fgedu.net.cn , http://www.itpux.com | |
| 数据库教程 : https://edu.51cto.com/lecturer/8020378.html |
FGMDU 1.0 - fgedu mysql dul
支持 MySQL 5.6/5.7/8.0/8.4/9.7, MariaDB, Percona
目标操作系统:Linux RHEL 5/6/7/8/9/10,Windows 7/8/8.1/10/11,Server 2008 R2/2012/2016/2019/2022

浙公网安备 33010602011771号