MySQL 物理数据目录恢复为 SQL 实战记录

这次拿到的不是普通的 .sql 备份,而是一整套 MySQL 的物理数据目录。目标很明确:把里面的业务库恢复出来,并导出成标准 SQL 文件,后续可以直接导入到其他 MySQL 实例中。

这篇文章记录一下完整过程,方便以后重复操作。

一、先判断手里的数据到底是什么

目录中能看到这些典型文件:

  • data/ibdata1
  • data/undo_001
  • data/undo_002
  • data/#innodb_redo/...
  • data/业务库目录/*.ibd

这说明手里的并不是逻辑备份,而是 MySQL 物理数据目录

其中:

  • 业务库目录下的 .ibd 是 InnoDB 表空间文件
  • ibdata1undo_*redo 相关文件属于 InnoDB 系统层

这个判断很关键,因为恢复策略会完全不同。

二、为什么这份数据能恢复

先看原始配置和错误日志,确认几个关键信息:

  • 原库版本是 MySQL 8.0.x
  • 使用的是 InnoDB
  • 配置里存在 lower_case_table_names=1
  • 日志显示数据库在近期还正常启动过
  • 没看到明显的系统表损坏或表空间损坏

所以最稳的路线不是去“猜表结构再导入 .ibd”,而是:

  1. 复制原始数据目录
  2. 用相同大版本 MySQL 挂载这个副本启动
  3. 启动成功后,再用 mysqldump 导出成标准 SQL

这样做的好处是:不碰原始数据,恢复成功率也更高

三、实际恢复步骤

1. 先复制一份数据副本

原始目录不要直接操作,先复制到单独的恢复目录。

后续所有启动、测试、导出动作都只针对副本进行。

2. 写一个恢复配置

恢复时补一份最小化配置,核心参数包括:

  • character-set-server=utf8mb4
  • collation-server=utf8mb4_unicode_ci
  • lower_case_table_names=1
  • skip-grant-tables

其中 skip-grant-tables 用来跳过权限校验,方便先把数据读出来。

3. 用 Docker 起临时 MySQL

使用与原库一致的大版本镜像,例如:

mysql:8.0.45-oraclelinux9

挂载方式:

  • 把恢复副本挂到容器的 /var/lib/mysql
  • 把恢复配置挂到容器的 /etc/my.cnf

启动后如果日志显示 InnoDB 初始化成功,并进入 ready for connections,就说明这份物理数据目录大概率是可用的。

4. 验证目标库和表

启动后先检查:

  • 目标数据库是否存在
  • 业务表是否能正常列出
  • 关键表是否能执行 SELECT COUNT(*)

这一步的意义是确认恢复已经不仅仅是“能启动”,而是 表结构和数据都能被 MySQL 正常识别

5. 导出标准 SQL

容器能正常读库后,直接使用 mysqldump 导出。

导出的内容通常会包含:

  • CREATE DATABASE
  • USE 数据库名
  • 每张表的 DROP TABLE IF EXISTS
  • 每张表的 CREATE TABLE
  • 每张表的 INSERT INTO

到这里,物理数据就已经成功转换成标准逻辑 SQL 了。

四、导入本地 MySQL

导入时,本地 MySQL 可以直接使用命令行客户端执行 SQL 文件。

示例命令:

mysql -u用户名 -p -e "source /path/to/recovered.sql"

导入后再检查数据库是否存在,并对关键表执行 COUNT(*) 校验。

五、校验思路

恢复完成后,建议至少做这几项校验:

  • 检查数据库是否成功创建
  • 检查业务表数量是否正常
  • 对关键表执行 COUNT(*)
  • 随机抽查几条业务数据

只要这些都正常,基本可以确认恢复出的 SQL 是可用的。

六、过程中遇到的一个坑

这次还遇到了一个很典型的问题:

  • mysql 查询能正常执行
  • mysqldumpmysqlpump 连接本地 socket 不稳定

这种情况往往不是库坏了,而是:

  • 本机客户端版本太老
  • 客户端来源复杂,比如来自 Anaconda、Homebrew 或其他环境
  • 服务端和客户端存在大版本差异

因此如果 mysql 能查、库也正常,先不要急着怀疑恢复失败,先排查 客户端兼容性和连接方式

七、这次恢复的核心经验

这次实践里最重要的几点是:

  1. 先判断拿到的是逻辑备份还是物理数据目录
  2. 不直接操作原始数据,必须先复制副本
  3. 尽量使用与原库一致的大版本 MySQL 启动副本
  4. 能整库启动成功时,优先走 mysqldump 逻辑导出
  5. .ibd 级别的单表恢复是备选方案,不是第一选择

八、结论

这类恢复最稳的路线通常是:

复制副本 -> 同版本 MySQL 启动 -> 验证数据 -> 逻辑导出 SQL

如果你手里也是类似的目录结构,而不是 .sql 文件,优先考虑这条路线。通常比单独折腾 .ibd 导入更稳,也更容易保住完整业务数据。