有没有办法恢复删除的 mysql 数据库?

kew*_*ewl 8 mysql

我不小心在我的服务器上丢了一个 MySQL 数据库。有没有办法恢复被删除的数据库?

aku*_*sky 17

如果您行动迅速,则很有可能恢复您的数据库。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 数据恢复工具包。我将用它来说明取消删除恢复。

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

./stream_parser -f /path/to/disk/image
Run Code Online (Sandbox Code Playgroud)

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

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

./stream_parser -f /var/lib/mysql/ibdata1
Run Code Online (Sandbox Code Playgroud)

现在您需要从 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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

因此,您删除的表(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
Run Code Online (Sandbox Code Playgroud)

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

在帖子中查看更多详细信息:


atx*_*dba 11

没有简单的方法可以打破这个给你。如果您通过 phpmyadmin 或命令行删除数据库并不重要。它不见了。

人为错误是拥有良好备份方案的原因之一。

我不信教,但我会说一个祈祷,希望这不是什么太重要的事情。

  • 在这种情况下,我最好推荐的是卸载 datadir 所在的文件系统。如果需要,请关闭服务器。致电数据恢复服务并准备支付数千,如果不是数十,同时支付无担保的废话拍摄:-\ (8认同)
  • 如果将来任何处于类似情况的人阅读此内容,我认为还值得建议的是,如果您打算聘请数据恢复公司,请务必尽快卸载文件系统或将其设为只读。在文件系统上持续写入的时间越长,包含已删除文件的集群就越有可能被覆盖。 (3认同)