31 数据误删的恢复

31 数据误删的恢复

1 使用delete语句误删数据行

2 使用drop table或者truncate table语句误删除数据表

3 使用drop database语句误删数据库

4 使用rm命令误删整个mysql实例

误删行

如果使用delete语句误删了数据行,可以使用flushback工具通过闪回把数据恢复出来

Flushback恢复数据的原理,是修改binlog的内容,拿回原库重放,使用flushback工具恢复的前提是,需要确保binlog_format=rowbinlog_row_image=FULL.

具体恢复数据时,对单个事务做如下处理:

1 对于insert语句,对于的binlog event类型是Write_rows event,把它改成Delete_row event即可

2 同理,对于delete,也是将Delete_rows event改为Write_rows event;

而如果是Update_rows的话,binlog里面记录了数据行修改前和修改后的值,对调这行的位置即可

如果误操作不是一个,而是多个,比如下面3个事务

(A) delete ...

(B) insert ...

(C)update ...

现在要把数据库恢复这3个事务操作之前的状态,用flashback工具解析binlog后,写回主库的命令是:

(reverse C)update ...

(reverse B)delete ...

(reverse A)insert ...

也就是说,如果误删除数据涉及到了多个事务的话,需要将事务的顺序调过来再执行

需要说明的是,不建议这些操作直接在主库上进行回放

恢复数据比较安全的做法是,恢复出一个备份,或者找一个从库作为临时库,在这个临时库上执行这些操作,然后再将确认过的临时库的数据,恢复回主库。

防止在数据误删的情况下,业务逻辑又继续更改其他的数据,所以这时候单恢复这几行数据,而又未经确认的话,可能会出现对数据的二次破坏。

防止数据误删的事前预防,有两个建议

1 sql_safe_updates参数设置为on,这样一来,如果忘记在delete或者update的语句写where条件,或者where条件里面没有包含索引字段的话,这条语句的执行就会报错。

2 代码上线前,必须经过sql审计。

如果确定这个删除操作没问题的话,可以在delete语句中加上where条件,比如where id>0;

但是delete全表很慢的,而且需要写回滚日志、写redo、写binlog,所以从性能角度考虑,应该优先考虑使用truncate或者drop table命令。

使用delete命令删除的数据,可以用flashback来恢复,而使用truncate/drop tabledrop database命令删除的数据,就没有办法使用flashback来恢复。因为设置了binlog_format=row,执行这3个命令时,binlog里面只有一个truncate/drop语句,这些信息是恢复不出数据的。

误删库/

这种情况下,要想恢复数据,就需要使用全量备份,加增量日志的方式,这个方案要求线上有定期的全量备份,并且实时备份binlog

在这2个条件下,假如有人中午12点误删了一个库,恢复数据的流程如下:

1 取最近一次全备份,假设这个库一天一个备份,上次备份是当天0

2 用备份恢复出一个临时库 

3 从日志备份里面,取出凌晨0点之后的日志

4 把这些日志,除了误删除数据的语句外,全部应用到临时库 

--说明

1 为了加速数据恢复,如果这个临时库上有多个数据库,可以在使用mysqlbinlog命令时加一个--database参数,用来指定误删表所在的库,避免了在恢复数据时还要应用其他库的日志情况。

2 在应用日志的时候,需要跳过12点误操作的那个语句的binlog

--如果实例没有使用gtid,只能在应用到包含12点的binlog文件的时候,先用--stop-position参数执行到误操作之前的日志,然后在用--start-position从无操作之后的日志进行恢复

--如果使用使用gtid模式,就方便多了,假设误操作命令的gtidgtid1,那么只需要执行set gtid_next =gtid1;begin;commit;先把这个gtid加到临时实例的gtid结合,之后按顺序执行binlog的时候,就会自动跳过错误的语句。

不过,即使这样,使用mysqlbinlog方法恢复数据还是不够快,主要原因:

--1 如果是误删表,最好就是只恢复出这张表,也就是只重放这张表的操作,但是mysqlbinlog工具并不能指定解析一个表的日志。

--2 mysqlbinlog解析出日志应用,应用日志的过程就只能是单线程

一种加速的方法是,在用备份恢复出临时实例后,将这个临时实例设置成线上线上备库的从库,这样

start slave之前,先通过执行:

--1 change replication filter replicate_do_table = (table_name),命令,就可以让临时库只同步误操作的表。

--2 这样做也可以用到并行复制,来加速整个数据恢复的过程。

假设,我们发现当前临时实例需要的binlogmaster.000005开始,但是在备库执行show binlogs显示的最小的binlog文件是master.000007,意味着少了两个binlog文件,这时,就需要去binlog备份系统中找到这两个文件。

把之前删掉的binlog放回备库的操作:

--1 从备份系统下载master.000005master.000006这两个文件,放到备库的日志目录下

--2 打开日志目录文件master.index,在文件开头加入两行,内容分表是”./master.000005”和”./master.000006”

--3 重启备库,目的是要让备库重新识别这2个日志文件

--4 现在这个备库已经有临时库需要的所有binlog,建立主备关系,就可以正常同步。

上面两种方式恢复,主要的思路是:通过备份,加上应用binlog的方式。

但是,一个系统不可能备份无限的日志,还需要根据成本和磁盘空间资源,设定一个日志的保留天数,或者告知需要保存某个实例恢复到半个月内的任意时间,就表示备份系统保留的日志时间就至少是半个月。

延迟复制备库

一般的主备复制结构存在的问题是,如果主库上有个表被删除了,这个命令会很快发给从库,进而导致所有从库的数据表也一起被删除掉,延迟复制的备库是一种特殊的备库,通过change master to master_delay=n 命令,可以指定这个备库持续保持跟主库的有n秒的延时。

如果把n设置为3600,就代表如果主库上有数据被误删了,并且在1个小时发现了这个误命令,在延迟备库上,执行stop slave,然后跳过误操作的命令,就可以恢复数据。

预防误删库/表的方法

建议

--1 账号分离,避免写错命令

---我们只给业务开发同学DML权限,而不给truncate/drop权限,而如果业务开发人员有DDL需求的话,也可以通过开发管理系统得到支持。

---即使dba成员,日常也都有规定只使用只读账号,必要的时候才使用有更新权限的账号

--2制定操作规范,避免写错要删除的表名

---在删除数据表之前,必须先对表做改名操作,然后,观察一段时间,确保对业务无影响以后再删除这张表。

---改表名的时候,要求给表名加固定的后缀,比如to_be_deleted,然后删除表的动作必须通过管理系统执行,并且管理系统删除表的时候,而能删除固定后缀的表。

rm 删除数据

对于一个有高可用机制的mysql集群来说,只要不是恶意把整个集群删除,而是删除其中某一个节点的数据的话,ha系统就会开始工作,选出一个新的主库,从而保证整个集群的正常工作。

现在不止是DBA有自动化系统,SA(系统管理员)也有自动管理系统,建议就是尽量把备份跨机房,或者跨城市。

小结

强调的是,预防远比处理的意义来得更大

另外,在mysql的集群方案中,会时不时得用到备份来恢复实例,因此定期检查备份的有效性也很有必要,如果是业务开发,可以用show grants命令查看账户的权限,如果权限过大,可以建议分配权限低一些的账号,也可以评估业务的重要性,和dba商量备份的周期,是否有必要创建延迟复制的备库等等。

数据和服务的可靠性不止是运维团队的工作,最终是各个环节一起保障的结果。

关于空表的间隙的定义

一个空表就只有一个间隙,在空表上执行

begin;
select * from t where id>1 for update;

这个查询语句加锁的范围是next-key lock(-无穷,supermum]

CREATE TABLE `t31` (
  `id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
(system@127.0.0.1:3306) [test]> SET SESSION tx_isolation='REPEATABLE-READ';

 

SESSION A

SESSION B

begin;

select * from t31 where id>1 for update;

 

 

insert into t31 values(2);(blocked)

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

 

 

--show engine innodb stauts\G;

 

转载于:https://www.cnblogs.com/yhq1314/p/10774433.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值