MySQL沒有備份情況下誤刪除表恢復


一、下載安裝

1.1 下載地址

git clone https://github.com/twindb/undrop-for-innodb.git

1.2 安裝

安裝依賴包

yum install -y make gcc flex bison

編譯安裝

cd undrop-for-innodb
make

增加用於恢復表結構的工具sys_parse

gcc `$basedir/bin/mysql_config --cflags` `$basedir/bin/mysql_config --libs` -o sys_parser sys_parser.c

$basedir 是 MySQL的安裝路徑

 

二、開始測試

2.1 測試數據

undrop-for-innodb中帶了一個 sakila 庫,不過我在測試的時候,用的是官方的,address 表有一個字段類型是 geometry。恢復的時候報錯,有興趣的朋友可以試一下

下載地址 https://dev.mysql.com/doc/index-other.html

 

2.2 刪除表

set foreign_key_checks = 0;
checksum table customer;
+-----------------+-----------+
| Table           | Checksum  |
+-----------------+-----------+
| sakila.customer | 399782750 |
+-----------------+-----------+

drop table customer;

checksum table 用來做恢復后的校驗

 

2.3 數據恢復

2.3.1 表結構恢復

使用工具 stream_parser 解析文件內容。

./stream_parser -f /data/mysql/mysql_3306/data/ibdata1

 

執行完畢后會在當前目錄下生成文件夾 pages-ibdata1 , 目錄下按照每個頁為一個文件,分為索引頁和數據較大的 BLOB 頁。系統表的話,是存在索引頁中的。使用另外一個重要的工具 c_parser 來解析頁的內容。

./c_parser -4Df pages-ibdata1/FIL_PAGE_INDEX/0000000000000001.page -t dictionary/SYS_TABLES.sql > dumps/default/SYS_TABLES 2> dumps/default/SYS_TABLES.sql
./c_parser -4Df pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page -t dictionary/SYS_INDEXES.sql > dumps/default/SYS_INDEXES 2> dumps/default/SYS_INDEXES.sql 
./c_parser -4Df pages-ibdata1/FIL_PAGE_INDEX/0000000000000002.page -t dictionary/SYS_COLUMNS.sql > dumps/default/SYS_COLUMNS 2> dumps/default/SYS_COLUMNS.sql
./c_parser -4Df pages-ibdata1/FIL_PAGE_INDEX/0000000000000004.page -t dictionary/SYS_FIELDS.sql > dumps/default/SYS_FIELDS 2> dumps/default/SYS_FIELDS.sql

參數解析:

  • 4 表示文件格式是 REDUNDANT,系統表的格式默認值。另外可以取值 5 表示 COMPACT 格式,6 表示 MySQL 5.6 格式。
  • D 表示只恢復被刪除的記錄。
  • f 后面跟着文件。
  • t 后面跟着 CREATE TABLE 語句,需要根據表的格式來解析文件。

得到的結果 ‘SYS_TABLES’ 字段后面的就是系統表 SYS_TABLE 中對應存的記錄。

 

創建恢復數據庫 recover,用來存放恢復的系統表

create database recover

導入系統表

mysql recover < dictionary/SYS_TABLES.sql 
mysql recover < dictionary/SYS_INDEXES.sql
mysql recover < dictionary/SYS_FIELDS.sql 
mysql recover < dictionary/SYS_COLUMNS.sql

mysql recover < dumps/default/SYS_TABLES.sql 
mysql recover < dumps/default/SYS_INDEXES.sql
mysql recover < dumps/default/SYS_FIELDS.sql 
mysql recover < dumps/default/SYS_COLUMNS.sql

dictionary目錄下是建表SQL,dumps/default/是剛才解析 page 得到的sql

 

解析表結構

./sys_parser -h'127.0.0.1' -uroot -p'abc_1234' -d recover sakila/customer
CREATE TABLE `customer`(
    `customer_id` SMALLINT UNSIGNED NOT NULL,
    `store_id` TINYINT UNSIGNED NOT NULL,
    `first_name` VARCHAR(45) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NOT NULL,
    `last_name` VARCHAR(45) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' NOT NULL,
    `email` VARCHAR(50) CHARACTER SET 'utf8' COLLATE 'utf8_general_ci',
    `address_id` SMALLINT UNSIGNED NOT NULL,
    `active` TINYINT NOT NULL,
    `create_date` DATETIME NOT NULL,
    `last_update` TIMESTAMP,
    PRIMARY KEY (`customer_id`)
) ENGINE=InnoDB;

對比發現,恢復出來的 CREATE TABLE 語句相比原來創建的語句信息量有點缺少,因為 innodb 系統表里面存的數據相比 frm 文件是不足的,比如 AUTO_INCREMENT, DECIMAL 類型的精度信息都會缺失,也不會恢復二級索引,外建等。

 

2.3.2 表數據恢復

找到表 customer 的 table_id

grep customer dumps/default/SYS_TABLES
00000018501F    3C00000188063B    SYS_TABLES    "sakila/customer"    480    9    33    0    80    ""    475
00000018501F    3C00000188063B    SYS_TABLES    "sakila/customer"    480    9    33    0    80    ""    475

 

再根據 table_id 找到 index_id

grep 480 dumps/default/SYS_INDEXES
00000018501F    3C0000018802CB    SYS_INDEXES    480    848    "PRIMARY"    1    3    475    4294967295
00000018501F    3C00000188033D    SYS_INDEXES    480    849    "idx\_fk\_store\_id"    1    0    475    4294967295
00000018501F    3C0000018803AF    SYS_INDEXES    480    850    "idx\_fk\_address\_id"    1    0    475    4294967295
00000018501F    3C000001880421    SYS_INDEXES    480    851    "idx\_last\_name"    1    0    475    4294967295
00000018501F    3C0000018802CB    SYS_INDEXES    480    848    "PRIMARY"    1    3    475    4294967295
00000018501F    3C00000188033D    SYS_INDEXES    480    849    "idx\_fk\_store\_id"    1    0    475    4294967295
00000018501F    3C0000018803AF    SYS_INDEXES    480    850    "idx\_fk\_address\_id"    1    0    475    4294967295
00000018501F    3C000001880421    SYS_INDEXES    480    851    "idx\_last\_name"    1    0    475    4294967295

grep 480 是對應 SYS_TABLE 的 TALE ID,848對應的 INDEX_ID

MySQL5.6之后,默認 innodb_file_per_table = on 這種情況下每個表是保存在各自的 ibd 文件中的,當 drop table 之后 ,ibd 文件會被刪除,此時最好能夠設置磁盤整體只讀避免有其它進程重寫文件塊stream_parser 這個工具不但可以讀文件,還可以讀磁盤,會根據 innodb 數據格式把數據頁讀出來。

找到被刪除的 ibd 文件的掛載磁盤

df -h
Filesystem               Size  Used Avail Use% Mounted on
/dev/mapper/centos-root   46G   13G   33G  28% /
devtmpfs                 1.9G     0  1.9G   0% /dev
tmpfs                    1.9G     0  1.9G   0% /dev/shm
tmpfs                    1.9G   89M  1.8G   5% /run
tmpfs                    1.9G     0  1.9G   0% /sys/fs/cgroup
/dev/vda1               1014M  142M  873M  14% /boot
tmpfs                    379M     0  379M   0% /run/user/0

我的實驗環境是 /dev/mapper/centos-root

./stream_parser -f /dev/mapper/centos-root -t 50G

磁盤大小執行 stream_parser,-t 表示磁盤的大小。執行的時候需要注意磁盤空間。跑完之后,在 undrop-for-innodb目錄下會有一個 pages-centos-root 目錄,其他環境不知道叫什么。類似 pages-ibdata1目錄,下面依然是 FIL_PAGE_INDEX 跟 FIL_PAGE_TYPE_BLOB。我們要找的頁在 FIL_PAGE_INDEX 目錄下。

pwd
/root/undrop-for-innodb/pages-centos-root/FIL_PAGE_INDEX ll 0000000000000848.page 
-rw-r--r--. 1 root root 81920 Oct 22 01:25 0000000000000848.page

接下來解析 0000000000000848.page

./c_parser -6f pages-centos-root/FIL_PAGE_INDEX/0000000000000848.page -t customer.sql > dumps/default/customer 2> dumps/default/customer.sql

參數解析:

  • 6 表示 MySQL 5.6 格式,4 表示文件格式是 REDUNDANT,系統表的格式默認值。另外可以取值 5 表示 COMPACT 格式。
  • D 表示只恢復被刪除的記錄。
  • f 后面跟着文件。
  • t 后面跟着 CREATE TABLE 語句,需要根據表的格式來解析文件。customer.sql 是我們解析表結構的文件

有興趣的朋友可以看一下 dumps/default/customer.sql,是 load data 語法SQL

 

2.3.3 導入恢復的數據

mysql sakila < customer.sql

mysql sakila < dumps/default/customer.sql

沒有報錯就是導入成功了,接下來就是校驗數據了

checksum table customer;
+-----------------+-----------+
| Table           | Checksum  |
+-----------------+-----------+
| sakila.customer | 399782750 |
+-----------------+-----------+

跟刪除表前的校驗值是一樣的。恢復成功。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM