MySQL误删数据后切勿跑路

误删数据的几种操作

  • delete语句误删数据行
  • drop table或者truncate table误删数据表
  • drop database误删数据库
  • rm命令误删整个MySQL实例
如何事前预防误删数据?
  • 将sql_safe_updates参数设置为on,此时如果delete或者update忘记写where条件,或者where条件里面没有包含索引字段的话,这条语句执行会报错
  • 代码上线前,必须经过SQL审计
误删行数据恢复
误删行数据恢复可以使用Flashback工具 。
Flashback恢复数据的原理是通过修改binlog内容,拿回原库进行回放,前提是binlog_format=row和binlog_row_image=FULL 。
在使用Flashback进行恢复的时候,不建议在主库上进行操作,比较安全的做法是恢复出一个备份,或者找一个从库作为临时库,在这个临时库上执行操作,然后再将确认过的临时库的数据恢复到主库 。
误删库/表
drop table或者truncate table误删数据表无法通过Flashback工具恢复,因为binlog_format的格式即使是ROW模式,在binlog中记录的也只是一条drop table或者truncate语句,因此无法进行恢复 。
此时恢复的方式需要全量备份加增量日志的方式进行恢复,因此要求数据有定期的全量备份,并且实时备份binlog 。
假如某人在中午12点误删除了一个库里的某张表,恢复数据的流程如下:
  1. 取最近的一次全量备份,假设该库是一天一备,上次备份时间就是当天0点
  2. 用备份恢复出一个临时库
  3. 从日志备份里取出0点以后的日志
  4. 把这些日志,除了误删除数据的语句外,全部应用到临时库
  • 为了加速数据恢复,如果这个临时库上有多个数据库,在使用mysqlbinlog命令时可以增加--database参数指定误删的表所在的数据库,避免在恢复数据时还要应用其他库日志的情况
  • 应用日志在跳过误删语句的binlog时:如果原实例没有使用GTID模式,只能先通过--stop-position恢复到误操作之前的日志,然后再用--start-position从误删操作之后的日志继续执行;如果实例使用了GTID模式,只需要执行set gtid_nex=gtid1;begin;commit;将该GTID加到临时库的GTID集合,之后在应用binlog时会自动跳过误操作的语句
mysqlbinlog恢复数据慢的原因?
  • 如果我们只是误删的表,但是mysqlbinlog工具并不能指定只解析一个表的日志
  • mysqlbinlog解析出日志以后,应用日志的过程是单线程,无法使用并行复制 。
如何更快的恢复误删的表?
在用备份恢复出临时实例以后,将这个临时实例设置成线上备库的从库:
  • 将误删表的gtid加入临时库
  • 然后建临时库设置为线上备库的从库,临时库就可以并行复制备库的binlog
假设此时备库的binlog已经被删除,那么需要去binlog备份系统找到删掉的日志文件拷贝到日志目录下,假设文件名是master.000001,打开日志目录下的binlog的index文件,在开头加入master.000001,让备库重新识别此日志文件
延迟复制备库
以上恢复都具有时间不可控性,如果采用上述步骤进行恢复,建议开发成工具(甚至可以做自己的DBA自动化平台),并大量测试后进行使用,避免手动误操作带来更大的问题 。
一般的主备复制存在的问题是,假设主库上的表被删除,这个命令很快会被发给所有从库,进而导致从库的数据表也被一起误删除 。
【MySQL误删数据后切勿跑路】延迟复制备库是可以持续保持与主库有N秒延迟的备库 。
CHANGE MASTER TO MASTER_DELAY=N;假设这里N=3600,那么表示只要在1个小时以内发现了误删除,就可以的到备库上执行stop slave,再通过之前讲到的方法,跳过误操作的命令(比如将误删除的GTID加到实例集合中),就可以恢复出需要的数据 。
rm误删
只要你的集群是高可用,如果rm删除了某个节点(只要不是恶意删除所有节点),HA系统会自动开始工作,选出一个新的主库,从而保证集群工作 。




    推荐阅读