我不小心在我的服务器上删除了一个 MySQL 数据库。有什么方法可以恢复删除的数据库?
如果您行动迅速,则很有可能恢复您的数据库。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。