一尘不染

有没有办法恢复丢失的 mysql 数据库?

mysql

我不小心在我的服务器上删除了一个 MySQL 数据库。有什么方法可以恢复删除的数据库?


阅读 72

收藏
2022-10-17

共1个答案

一尘不染

如果您行动迅速,则很有可能恢复您的数据库。InnoDB 的机会更高,对于 MyISAM,它不是零,但很接近。

问题是当 MySQL 执行 DROP TABLE 或 DROP DATABASE(本质上是相同的)时,InnoDB 不会擦除数据。包含数据的页面仍在磁盘上。

根据 innodb_file_per_table 设置,恢复过程会有所不同。如果 innodb_file_per_table 为 OFF(默认到 5.5),则删除的表保留在 ibdata1 中。如果 innodb_file_per_table 为 ON(默认为 5.5),则删除的表位于相应的 .ibd 文件中。MySQL 在删除表时删除此文件。

首先要做的是停止任何可能的写入,这样您的表就不会被覆盖。如果 innodb_file_per_table 为 OFF,则足以停止 MySQL(kill -9 更好,但请确保先杀死 safe_mysqld)。如果 innodb_file_per_table 为 ON,则卸载 MySQL 存储其数据的分区。如果 datadir 在根分区上,我建议关闭服务器或至少拍摄磁盘映像。让我重复一遍,目标是防止 MySQL 或操作系统覆盖删除的表。

有一个工具允许在低级别使用 InnoDB 页面, TwinDB 数据恢复工具包。我将用它来说明 undrop 恢复。

您需要获取带有已删除表的媒体(ibdata1 或磁盘映像)并在其上找到 InnoDB 页面。工具包中的 stream_parser 工具可以做到这一点。

./stream_parser -f /path/to/disk/image

它将扫描文件,找到 InnoDB 页面并按类型和 index_id 对它们进行排序。index_id 是 InnoDB 用来引用索引的标识符。表存储在索引 PRIMARY 中。要找到 index_id 是您删除的表,您需要恢复 InnoDB 字典

InnoDB 字典存储在 ibdat1 文件中。您需要以与上述相同的方式扫描 ibdata1 文件:

./stream_parser -f /var/lib/mysql/ibdata1

现在您需要从 InnoDB 字典表 SYS_TABLES 和 SYS_INDEXES 中获取记录(假设您的表是 sakila.actor):

./c_parser -4Df pages-ibdata1/FIL_PAGE_INDEX/0000000000000001.page -t dictionary/SYS_TABLES.sql | grep sakila/actor
000000000B28  2A000001430D4D  SYS_TABLES  "sakila/actor"  158  4  1 0   0   ""  0

158是table_id,记住了。

./c_parser -4Df pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page -t dictionary/SYS_INDEXES.sql | grep 158
000000000B28    2A000001430BCA  SYS_INDEXES     158     376     "PRIMARY"       1       3       0       4294967295
000000000B28    2A000001430C3C  SYS_INDEXES     158     377     "idx\_actor\_last\_name"        1       0       0       4294967295

因此,您删除的表(sakila.actor)的 index_id 是 376。

现在您可以从 InnoDB index_id 376 获取已删除表的记录。您需要具有已删除表的表结构,即创建表时使用的 CREATE TABLE 语句。你在哪里可以得到它?要么来自旧备份,要么来自其他地方。也可以从 InnoDB 字典中恢复结构,但我不会在这个答案中介绍它。让我们假设你拥有它。

./c_parser -6f pages-ibdata1/FIL_PAGE_INDEX/0000000000000376.page -t actor.sql > dump.tsv 2> load_cmd.sql

c_parser 将记录作为制表符分隔的转储输出到标准输出。可以使用 LOAD DATA 命令加载转储。c_parser 将其打印到 stderr。

2022-10-17