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完整说明文档,涵盖程序介绍、功能特性、使用方法、典型案例、问题排查等全部内容。


目录

  1. 程序介绍
  2. 功能特性
  3. 支持环境
  4. 程序使用
  5. 程序各种案例场景与操作过程
  6. 常用问题与排查

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 在设计上遵循以下原则:

  1. 绕过实例,直读文件:不启动 mysqld,不连接 SQL 接口,直接以只读方式打开数据文件,避免对原始数据造成二次破坏。
  2. 零外部依赖:单一代码库、标准 C99、无第三方库,可静态编译后单文件部署到无网络环境。
  3. 跨平台一致体验:Linux 与 Windows 共享同一份源代码,命令行参数、输出格式、行为语义完全一致。
  4. 渐进式恢复策略:从"正常抽取"到"已删除记录恢复"再到"坏块启发式恢复"和"无字典暴力扫描",多级递进,先易后难,最大程度抢救数据。
  5. 安全优先:所有 I/O 操作只读,绝不修改源文件;所有内存分配带 OOM 处理;所有指针与边界检查齐全;遇到坏块自动降级而非崩溃退出。
  6. 详细进度反馈:抽取过程中实时输出每张表的表名、抽取行数、扫描进度,便于用户在大表恢复时监控状态。
  7. 命令简洁清晰:使用 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 模式):

  1. 显式 DDL 文件(--ddl 指定的单表 DDL)
  2. DDL 目录(--ddl-dir 下的 <table>.sql
  3. SDI 目录(--sdi-dir 下的 .sdi JSON)
  4. 数据目录同位置的 .frm 文件
  5. 数据目录同位置的 <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 通过搜索页面中的 infimumsupremum 字节标记来定位系统记录,从而重建页面结构:

  1. 在页面数据区域搜索 infimum 字符串(7 字节 + NULL)
  2. 在页面数据区域搜索 supremum 字符串(8 字节)
  3. 根据找到的位置推断记录链起始位置
  4. 尝试从残留的页面头字节中读取 heap_top、index_id 等信息
  5. 如果 heap_top 不可读,使用页面大小的 1/4 作为保守估计
  6. 遍历记录链提取所有可恢复的记录

限制:无法恢复 FIL 头和页面头同时损坏的页面;恢复的记录可能缺少部分元数据(如 index_id)。

BLOB 外部页面恢复(--blob-recovery

InnoDB 表包含 BLOB/TEXT 大字段时,数据可能存储在外部页面(BLOB page)中。记录中只保留 20 字节的引用指针:前 4 字节为实际数据长度,后 16 字节为指向外部页面的指针(space_id + page_no + offset)。FGMDU 通过:

  1. 扫描记录数据,检测是否包含 BLOB 引用
  2. 读取引用指向的外部 BLOB 页面
  3. 验证页面类型为 BLOB/ZBLOB
  4. 提取 BLOB 页面中的数据(跳过 8 字节 BLOB 头)
  5. 如果数据跨越多个 BLOB 页面,沿 BLOB 链追踪
  6. 链追踪安全措施:最大 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.hportable.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

递归扫描所有子目录,自动发现 .ibdibdata1 文件。

恢复输出格式(输出为 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 的坏块跳过机制可以最大程度地抢救坏块周围的可读数据,该机制自动启用,无需额外选项

工作原理(三级递进策略)

  1. 正常整页读取:首先尝试一次性读取整个页面(16KB)。如果成功,正常处理。
  2. 分块降级读取:如果整页读取失败,按 4096 字节 → 512 字节 → 1 字节的粒度逐块重试。可读部分填入缓冲区,不可读部分用零填充。
  3. 启发式恢复:对部分读取的页面,尝试搜索 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: 可能原因及解决方案:

  1. 文件不是 InnoDB 格式 - 使用 scan 命令检查
  2. 页面全部损坏 - 尝试 --raw-scan --recover-corrupt
  3. 数据在 ibdata1 而非 .ibd 中 - 使用 --data ibdata1路径
  4. 页面大小不匹配 - 使用 --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 错误时:

  1. 自动降级为分块读取(4096 → 512 → 1 字节)
  2. 可读部分填入缓冲区,不可读部分用零填充
  3. 对部分读取的页面尝试启发式恢复
  4. 坏块页面恢复的记录标记为 confidence=30
  5. 恢复完成后报告坏块统计信息

如果坏块非常严重,建议先用 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 模式:

  1. .ibd 文件已被新文件替换
  2. 需要在文件系统层面恢复被删除的旧 .ibd 文件
  3. 使用 extundeletetestdisk 等工具恢复
  4. 然后使用 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: 可能原因:

  1. 文件是 MyISAM 的 .MYD 而非 InnoDB 的 .ibd,scan 只支持 InnoDB
  2. 页面大小不匹配,尝试 --page-size 4096--page-size 32768
  3. 文件头部已损坏,FIL 头无法识别

Q12:recover 命令默认就启用了哪些选项?

A: 如果没有显式指定 --recover-deleted--recover-corrupt,recover 命令会自动默认启用这两个选项(安全优先)。如需禁用,请显式指定其他选项组合。--raw-scan 在没有 DDL 时也会自动启用。

6.2 日志级别

  • INFO:正常进度信息
  • WARN:警告,可能影响部分输出
  • ERROR:错误,可能导致恢复失败
  • DEBUG:调试信息(使用 -v 启用)

6.3 最佳实践

  1. 永远在副本上操作:不要直接操作原始数据文件,先 cp -a 创建副本
  2. 先扫描后恢复:使用 scan 命令评估损坏程度,制定恢复策略
  3. 先正常后恢复:先尝试 unload,失败后再用 recover,从易到难递进
  4. 保留恢复元数据:使用 --recover-meta 记录数据来源(页号、可信度)
  5. 分批恢复:使用过滤选项分数据库/表恢复,避免一次性处理过多数据
  6. 验证数据:恢复后务必检查数据的完整性和正确性,特别是 confidence=30 的记录
  7. 坏块先镜像:对于物理坏块磁盘,先用 ddrescue 创建镜像再操作
  8. 大文件用 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

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