事故背景
习惯性的使用快捷键执行SQL脚本,在切换数据源时误操作使用了线上数据库,执行了SQL:
delete from base_ppl_331000 where true;导致业务主表数据被清空。
因为我们是传统行业,做的政府业务,所以数据有专门的部门维护,我们是没有数据库服务器权限的,因此做不了数据闪回等操作。
项目经理担心事情被上级领导知道,所以要来了数据库备份文件,要我们自己解决问题,恢复数据。
数据库:阿里云rds-mysql 5.7.26
数据量:490w
恢复用时:1h
恢复方式:使用ibd文件恢复数据
备份文件类型:RDS的全库物理备份文件:hins262_data_20210814010323.tar.gz
恢复过程
使用命令获取需要还原的表的创建语句
show create table base_ppl_331000;
1、安装一台MySQL 数据库,用于恢复备份中的表base_ppl_331000
2、在自己的MySQL中,使用刚刚的sql创建表 base_ppl_331000
3、修改自己的MySQL配置,修改/etc/my.cnf文件,增加一个“强制恢复”相关的参数:innodb_force_recovery=1
4、重启MySQL
[admin@app-94 ~]$ systemctl stop mysqld.service;
[admin@app-94 ~]$ systemctl start mysqld.service
[admin@app-94 ~]$ service mysqld status
5、执行SQL:
alter table testTable discard tablespace;让表结构和表空间脱离
6、在linux 上解压RDS 物理备份文件:
# 创建一个文件存储目录
[admin@app-94 ~]$ mkdir /home/mysql/data
# 将压缩文件解压至存储目录
[admin@app-94 ~]$ tar -izxvf hins262_data_20210814010323.tar.gz -C /home/mysql/data
7、在备份文件中找到你需要的ibd文件,并替换他
# 获取ibd文件位置
[admin@app-94 ~]# find -name base_ppl_331000.ibd
./data/basedata/base_ppl_331000.ibd
# 暴力获取mysql 位置
[admin@app-94 ~]# find / -name mysql -print
/etc/logrotate.d/mysql
/etc/selinux/targeted/active/modules/100/mysql
/root/mydata/data/mysql
/var/lib/mysql
/var/lib/mysql/mysql
/usr/bin/mysql
/usr/lib64/mysql
/usr/share/mysql
/usr/local/bin/mysql
# 进入mysql文件目录
[admin@app-94 ~]# cd /var/lib/mysql
# 找到ibd文件位置
[admin@app-94 ~]# find -name base_ppl_331000.ibd
./mydatabase/base_ppl_331000.ibd
# 替换ibd文件
[admin@app-94 ~]# cp data/basedata/base_ppl_331000.ibd /var/lib/mysql/mydatabase/
# 对ibd文件赋权
[admin@app-94 ~]# chown -R mysql.mysql base_ppl_331000.ibd
8、重新导入表空间:
alter table base_ppl_331000 import tablespace;
9、使用工具导出SQL insert语句,我的SQL文件mydatabase_base_ppl_331000.sql 导出后有4.94G
10、处理SQL文件,导入数据到线上库
# 如果有的话,删掉sql中的多余数据库名称
[admin@app-94 ~]# perl -pi.bak -e "s/mydatabase.//gi" mydatabase_base_ppl_331000.sql
# 拆分sql文件,在多台服务器中执行
[admin@app-94 ~]# split -l 500000 mydatabase_base_ppl_331000.sql largeFile000
# 登录线上数据库
[admin@app-94 ~]# mysql -u root -p
# 开启日志
[admin@app-94 ~]# mysql> SET GLOBAL log_output = 'TABLE';
[admin@app-94 ~]# mysql> SET GLOBAL general_log = 'ON';
# 使用外挂脚本的方式执行SQL文件
[admin@app-94 ~]# mysql> source ~/largeFile000aa.sql test.sql
# 如果中途哪台机器断掉,可以带条件查看最后一条insert,之后单独处理
# 例如:查询Insert SQL
[admin@app-94 ~]# mysql> select * from mysql.general_log where user_host = 'root[root] @ [192.168.4.232]' and argument like '%INSERT%' order by event_time desc;
11、修改/etc/my.cnf文件,修改
innodb_force_recovery=0
12、重启MySQL
更好的处理方案
1、开启MySQL的
sql_safe_updates, 当sql_safe_updates设置为1时
UPDATE:要有where,并查询条件必须使用为索引字段,或者使用limit,或者两个条件同时存在,才能正常执行。
DELETE:where条件中带有索引字段可删除,where中查询条件不是索引,得必须有limit。主要是防止UPDATE和DELETE 没有使用索引导致变更及删除大量数据。系统参数默认值为0
show variables like 'sql_safe_updates';
set global sql_safe_updates=1;
2、最好是在数据被删除之后,及时联系DBA,操作数据快速回滚(闪回),数据闪回需要服务器权限和若干组件,不熟悉的话不要自己做,delete 语句只是标记数据为删除,但不会回收磁盘空间,只是被标记删除的位置可以被复用
3、如果是单表恢复,在沟通时直接索要.bd文件,不要像我们这样给过来的是几十个G的全库备份