mysql 备份表无法恢复_MySQL删库不跑路-无备份Drop表恢复

3d17ec87ff86c1f17d864b4c456eee3c.png

MySQL删库不跑路-无备份Drop恢复

说在前头

库一定要备份!!!

库一定要备份!!!

库一定要备份!!!

由于当前环境基本上都会开启 innodb_file_per_table ,因此测试 innodb_file_per_table = 1 情况下的数据恢复,innodb_file_per_table = 0 的操作差不多

  • 不要太指望工具能恢复户多少数据,会有多种情况花式丢页数据,导致无法恢复
  • 现象1:drop table 后,有DDL操作 + insert ..select 操作,丢失页
  • 现象2:使用命令行shutdown库或kill 进程,丢失页
  • 各种花式丢页,所以备份一定要做好,不要太指望这个

环境

MySQL 5.7.27-log

系统: CentOS Linux release 7.6.1810

恢复工具: undrop-for-innodb

[ https:// github.com/twindb/undro p-for-innodb ](twindb/undrop-for-innodb)

恢复工具安装

git clone twindb/undrop-for-innodb
yum install -y make gcc flex bison
cd undrop-for-innodb/
make
完成后当前目录下出现可执行文件 c_parserstream_parser

表结构恢复工具安装

cd undrop-for-innodb/
[root@testinit undrop-for-innodb]# gcc `/usr/local/mysql/bin/mysql_config --cflags` `/usr/local/mysql/bin/mysql_config --libs` -o sys_parser sys_parser.c
/usr/local/mysql/bin 是当前mysql安装的 basedir,完成后当前目录下会出现可执行文件 sys_parser

模拟数据表误删

root@mysqldb 04:27:  [none]> create database dtest;
Query OK, 1 row affected (0.00 sec)

root@mysqldb 04:27:  [(none)]> use dtest
Database changed

root@mysqldb 04:27:  [(dtest)]>
CREATE TABLE `dtest1` ( `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` varchar(10) DEFAULT NULL,
  `b` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4;

root@mysqldb 22:38:  [dtest]> insert into dtest1 values(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5);

root@mysqldb 04:27:  [dtest]> update dtest1 set b = '222' where id = 2;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

root@mysqldb 04:27:  [dtest]> checksum table dtest1;
+--------------+------------+
| Table        | Checksum   |
+--------------+------------+
| dtest.dtest1 | 3175768141 |
+--------------+------------+
1 row in set (0.00 sec)

root@mysqldb 04:28:  [dtest]> select * from dtest1;
+----+------+------+
| id | a    | b    |
+----+------+------+
|  1 | 1    | 1    |
|  2 | 2    | 222  |
|  3 | 3    | 3    |
|  4 | 4    | 4    |
|  5 | 5    | 5    |
+----+------+------+
5 rows in set (0.00 sec)

root@mysqldb 04:30:  [dtest]> create table dtest2 like dtest1;
Query OK, 0 rows affected (0.02 sec)

root@mysqldb 04:30:  [dtest]> create table dtest3 like dtest1;
Query OK, 0 rows affected (0.01 sec)

root@mysqldb 04:30:  [dtest]> insert into dtest2 select * from dtest1;
Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0

root@mysqldb 04:30:  [dtest]> alter table dtest3 add c varchar(10);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

root@mysqldb 04:32:  [dtest]> insert into dtest3 select t.*,'123456' from dtest1 t;
Query OK, 5 rows affected (0.00 sec)
Records: 5  Duplicates: 0  Warnings: 0

# 模拟误删表
root@mysqldb 04:32:  [dtest]> drop table dtest1;
Query OK, 0 rows affected (0.00 sec)

# 误删后肯定还会有其他业务会在操作其他表,模拟还有其他操作
root@mysqldb 04:34:  [dtest]> update dtest2 set b = 'bbbbbbbb' where id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

备份复制一份进行恢复【也可以不操作这一步,直接分析源库的】

  • 可以不停止源MySQL,但若出现DDL操作,可能会导致数据丢失恢复不出来
  • 停机并拷贝备份,业务无法停机也能直接操作下一步,停机是为了降低莫名丢页问题
  • 不要 kill 进程,不要在mysql命令项内执行 shutdown来关闭Mysql
mysqladmin -uroot -S /tmp/mysql.sock shutdown 或 service mysqld stop
cp -R /data/mysql_data/ /data/mysql_data2

获取表对应页

当前操作在源库上操作,mysql已关闭

1-解析ibdata1

[root@testinit undrop-for-innodb]# ./stream_parser -f /data/mysql_data/ibdata1
Opening file: /data/mysql_data/ibdata1
File information:

ID of device containing file:        64768
inode number:                     16935187
protection:                         100640 (regular file)
number of hard links:                    1
user ID of owner:                      998
group ID of owner:                    1000
device ID (if special file):             0
blocksize for filesystem I/O:         4096
number of blocks allocated:        2097152
time of last access:            1589574685 Sat May 16 04:31:25 2020
time of last modification:      1589574876 Sat May 16 04:34:36 2020
time of last status change:     1589574876 Sat May 16 04:34:36 2020
total size, in bytes:           1073741824 (1.000 GiB)

Size to process:                1073741824 (1.000 GiB)
Worker(0): 3.12% done. 2020-05-16 04:37:21 ETA(in 00:00:41). Processing speed: 24.000 MiB/sec
...省略
All workers finished in 11 sec

2-解析数据文件所在磁盘页

[root@testinit undrop-for-innodb]# df -k
Filesystem              1K-blocks    Used Available Use% Mounted on
/dev/mapper/centos-root  15767552 8275312   7492240  53% /
devtmpfs                   485780       0    485780   0% /dev
tmpfs                      497948       0    497948   0% /dev/shm
tmpfs                      497948    7728    490220   2% /run
tmpfs                      497948       0    497948   0% /sys/fs/cgroup
/dev/sda1                 1038336  135380    902956  14% /boot
tmpfs                       99592       0     99592   0% /run/user/0

[root@testinit undrop-for-innodb]# ./stream_parser -f /dev/mapper/centos-root -t 15767552k
Opening file: /dev/mapper/centos-root
File information:

ID of device containing file:            5
inode number:                        18278
protection:                          60660 (block device)
number of hard links:                    1
user ID of owner:                        0
group ID of owner:                       6
device ID (if special file):         64768
blocksize for filesystem I/O:         4096
number of blocks allocated:              0
time of last access:            1589538693 Fri May 15 05:31:33 2020
time of last modification:      1589538693 Fri May 15 05:31:33 2020
time of last status change:     1589538693 Fri May 15 05:31:33 2020
total size, in bytes:                    0 (0.000 exp(+0))

Size to process:               16145973248 (15.037 GiB)
Worker(0): 1.09% done. 2020-05-15 05:52:55 ETA(in 00:11:07). Processing speed: 22.813 MiB/sec
Worker(0): 2.13% done. 2020-05-15 05:46:34 ETA(in 00:04:43). Processing speed: 53.234 MiB/sec
...省略
All workers finished in 85 sec
完成后当前目录下会生成俩个page开头的文件
pages-centos-root
pages-ibdata1

解析页获取表结构与表对应页ID

1-找到表的ID

[root@testinit undrop-for-innodb]# ./c_parser -6Df ./pages-ibdata1/FIL_PAGE_INDEX/0000000000000001.page -t ./dictionary/SYS_TABLES.sql | grep 'dtest/dtest1'
SET FOREIGN_KEY_CHECKS=0;
LOAD DATA LOCAL INFILE '/root/undrop-for-innodb/dumps/default/SYS_TABLES' REPLACE INTO TABLE `SYS_TABLES` CHARACTER SET UTF8 FIELDS TERMINATED BY 't' OPTIONALLY ENCLOSED BY '"' LINES STARTING BY 'SYS_TABLESt' (`NAME`, `ID`, `N_COLS`, `TYPE`, `MIX_ID`, `MIX_LEN`, `CLUSTER_NAME`, `SPACE`);
-- STATUS {"records_expected": 54, "records_dumped": 6, "records_lost": true} STATUS END
000000000B06	260000002F0221	SYS_TABLES	"dtest/dtest1"	40	3	33	0	80	""	28
000000000B06	260000002F0221	SYS_TABLES	"dtest/dtest1"	40	3	33	0	80	""	28
表ID为表名后面的那个数字,这里为 40

2-利用找出来的表ID,查找数据所在的磁盘页ID

[root@testinit undrop-for-innodb]# ./c_parser -6Df ./pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page -t ./dictionary/SYS_INDEXES.sql | grep 40
SET FOREIGN_KEY_CHECKS=0;
LOAD DATA LOCAL INFILE '/root/undrop-for-innodb/dumps/default/SYS_INDEXES' REPLACE INTO TABLE `SYS_INDEXES` CHARACTER SET UTF8 FIELDS TERMINATED BY 't' OPTIONALLY ENCLOSED BY '"' LINES STARTING BY 'SYS_INDEXESt' (`TABLE_ID`, `ID`, `NAME`, `N_FIELDS`, `TYPE`, `SPACE`, `PAGE_NO`);
-- STATUS {"records_expected": 64, "records_dumped": 8, "records_lost": true} STATUS END
000000000B06	260000002F0145	SYS_INDEXES	40	41	"PRIMARY"	1	3	28	4294967295
000000000B06	260000002F0145	SYS_INDEXES	40	41	"PRIMARY"	1	3	28	4294967295
一般会在 0000000000000003.page 中找到,若不存在,则使用下面的语句循环查一下看看
for i in `ls ./pages-ibdata1/FIL_PAGE_INDEX/`; do echo "$i"; ./c_parser -6Df ./pages-ibdata1/FIL_PAGE_INDEX/$i -t ./dictionary/SYS_INDEXES.sql | grep -w 40; done
这里可以看到,ID 40 对应的page页为 41,41就是表数据所在磁盘页

3-查看对应的页是否存在

查看恢复页存不存在,不存在则凉凉,当前示例需要查看对应的页 41 是否存在

ls ./pages-centos-root/FIL_PAGE_INDEX/

4-获取表结构(若已知被删除表的表结构,这一步跳过)

上面的页已分析完毕,可以启动mysql了【之前没关的话,忽略】

mysqld_safe --user=mysql &

4.1-执行recover_dictionary.sh

执行undrop-for-innodb目录下的recover_dictionary.sh,会创建一个`test`库,并生成SYS开头的4张表,若test库已存在,则直接生成在这个库下

[root@testinit undrop-for-innodb

生成库表如下:

root@mysqldb 06:21:  [(none)]> use test;
Database changed

root@mysqldb 06:21:  [test]> show tables;
+----------------+
| Tables_in_test |
+----------------+
| SYS_COLUMNS    |
| SYS_FIELDS     |
| SYS_INDEXES    |
| SYS_TABLES     |
+----------------+
4 rows in set (0.00 sec)

可以查看字典信息同样得知表ID与对应页ID

root@mysqldb 06:22:  [(none)]> use test
Database changed

# 获得表ID 40
root@mysqldb 06:22:  [test]> select * from SYS_TABLES where name like 'dtest/dtest1';
+--------------+----+--------+------+--------+---------+--------------+-------+
| NAME         | ID | N_COLS | TYPE | MIX_ID | MIX_LEN | CLUSTER_NAME | SPACE |
+--------------+----+--------+------+--------+---------+--------------+-------+
| dtest/dtest1 | 40 |      3 |   33 |      0 |      80 |              |    28 |
+--------------+----+--------+------+--------+---------+--------------+-------+
1 row in set (0.00 sec)

# 获得页ID 41
root@mysqldb 06:22:  [test]> select * from SYS_INDEXES where table_id=40;
+----------+----+---------+----------+------+-------+------------+
| TABLE_ID | ID | NAME    | N_FIELDS | TYPE | SPACE | PAGE_NO    |
+----------+----+---------+----------+------+-------+------------+
|       40 | 41 | PRIMARY |        1 |    3 |    28 | 4294967295 |
+----------+----+---------+----------+------+-------+------------+
1 row in set (0.00 sec)

4.2-获得结构

# 创建libmysqlclient.so.20软链,否则可能报错
[root@testinit undrop-for-innodb]# ln -s /usr/local/mysql-5.7.27-linux-glibc2.12-x86_64/lib/libmysqlclient.so.20 /usr/lib64/libmysqlclient.so.20

# 密码要写上去,可以创建个权限高一点的,用完删除这个用户
[root@testinit undrop-for-innodb]# ./sys_parser -h 127.0.0.1 -u root -p123456 -d test dtest/dtest1
CREATE TABLE `dtest1`(
	`id` INT NOT NULL,
	`a` VARCHAR(10) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci',
	`b` VARCHAR(10) CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_general_ci',
	PRIMARY KEY (`id`)
) ENGINE=InnoDB;

解析页数据导出

1-创建需恢复表的表结构SQL

[root@testinit undrop-for-innodb]# cat /tmp/dtest1.sql
CREATE TABLE `dtest1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `a` varchar(10) DEFAULT NULL,
  `b` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

2 查看数据是否存在【可略】

# 查看数据
[root@testinit undrop-for-innodb]# ./c_parser -6f pages-centos-root/FIL_PAGE_INDEX/0000000000000041.page -t /tmp/dtest1.sql |head -5
SET FOREIGN_KEY_CHECKS=0;
LOAD DATA LOCAL INFILE '/root/undrop-for-innodb/dumps/default/dtest1' REPLACE INTO TABLE `dtest1` CHARACTER SET UTF8 FIELDS TERMINATED BY 't' OPTIONALLY ENCLOSED BY '"' LINES STARTING BY 'dtest1t' (`id`, `a`, `b`);
-- STATUS {"records_expected": 5, "records_dumped": 5, "records_lost": false} STATUS END
-- Page id: 3, Format: COMPACT, Records list: Valid, Expected records: (5 5)
000000000907	A7000000250110	dtest1	1	"1"	"1"
00000000090C	2A000000300110	dtest1	2	"2"	"222"
000000000907	A7000000250128	dtest1	3	"3"	"3"
000000000907	A7000000250134	dtest1	4	"4"	"4"
00000B18    B3000000290134    da    4    "4"    "4"
0000000000000041.page 上面查出的对应的页ID文件

3-创建指定的恢复目录

mkdir -p /root/undrop-for-innodb/dumps/default

4-数据导出

./c_parser -6f pages-centos-root/FIL_PAGE_INDEX/0000000000000041.page -t /tmp/dtest1.sql > dumps/default/dtest1 2> dumps/default/dtest1.sql
dumps/default 这个目录不要更改

恢复数据到mysql

# 登陆mysql
mysql -uroot -p

# 切换到指定库
root@mysqldb 06:25:  [(none)]> use dtest

# 生成对应表,或手动创建
root@mysqldb 06:25:  [dtest]> source /tmp/dtest1.sql

# 导入数据
root@mysqldb 06:26:  [dtest]>  source /root/undrop-for-innodb/dumps/default/dtest1.sql
Query OK, 0 rows affected (0.00 sec)

Query OK, 5 rows affected (0.00 sec)
Records: 5  Deleted: 0  Skipped: 0  Warnings: 0

数据验证

root@mysqldb 06:28:  [dtest]> show tables;
+-----------------+
| Tables_in_dtest |
+-----------------+
| dtest1          |
| dtest2          |
| dtest3          |
+-----------------+
3 rows in set (0.00 sec)

root@mysqldb 06:28:  [dtest]> select * from dtest1;
+----+------+------+
| id | a    | b    |
+----+------+------+
|  1 | 1    | 1    |
|  2 | 2    | 222  |
|  3 | 3    | 3    |
|  4 | 4    | 4    |
|  5 | 5    | 5    |
+----+------+------+
5 rows in set (0.00 sec)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值