1. 根据误操作时间定位binlog位置
找到数据库的binlog存放位置,当前正在使用的binlog文件里面就有我们要恢复的数据。一般生产环境中的binlog文件都是几百M乃至上G的大小,我们不能逐行去找被删除的数据在什么位置,所以记住误操作的时间很重要,我们可以通过mysqlbinlog命令的--start-datetime参数快速定位数据位置。比如误操作时间为20181104151800,解析出的binlog内容:

[root@cos7-jiang mysql]# mysqlbinlog -vv --start-datetime='2018-11-04 15:18:00' on.000004|more
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#700101 8:00:00 server id 1 end_log_pos 120 CRC32 0x199f2da4 Start: binlog v 4, server v 5.6.42-log created 700101 8:00:
00
# Warning: this binlog is either in use or was not closed properly.
BINLOG '
AAAAAA8BAAAAdAAAAHgAAAABAAQANS42LjQyLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAXAAEGggAAAAICAgCAAAACgoKGRkAAaQt
nxk=
'/*!*/;
# at 120
#181104 15:18:37 server id 1 end_log_pos 192 CRC32 0x2224f8de Query thread_id=16 exec_time=0 error_code=0
SET TIMESTAMP=1541315917/*!*/;
SET @@session.pseudo_thread_id=16/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1075838976/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C latin1 *//*!*/;
SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 192
#181104 15:18:37 server id 1 end_log_pos 252 CRC32 0x65fbbe3b Table_map: `test`.`person` mapped to number 85
# at 252
#181104 15:18:37 server id 1 end_log_pos 435 CRC32 0x005d1b39 Delete_rows: table id 85 flags: STMT_END_F BINLOG '
TZ3eWxMBAAAAPAAAAPwAAAAAAFUAAAAAAAEABHRlc3QABnBlcnNvbgAGAw/+DwMDBgoA/gEKAD47
vvtl
TZ3eWyABAAAAtwAAALMBAAAAAFUAAAAAAAEAAgAG/8ABAAAAAmppATEDd2VyqEA0AGpqyADAAgAA
AANsdW8BMQN3ZXKcQjQAJ2zZAMADAAAAAnl1ATAEamVndfombwA3JyEBwAQAAAACZGEBMAdiZWlq
aW5nOgZQAFfZQADABQAAAAJnagEwB2JlaWppbmcSBlAAh+jOAMAGAAAABHlhbmcBMAduYW5qaW5n
cg5MAIdSqwo5G10A
'/*!*/;
### DELETE FROM `test`.`person`
### WHERE
### @1=1 /* INT meta=0 nullable=0 is_null=0 */
### @2='ji' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
### @3='1' /* STRING(1) meta=65025 nullable=1 is_null=0 */
### @4='wer' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
### @5=3424424 /* INT meta=0 nullable=1 is_null=0 */
### @6=13134442 /* INT meta=0 nullable=1 is_null=0 */
### DELETE FROM `test`.`person`
### WHERE
### @1=2 /* INT meta=0 nullable=0 is_null=0 */
### @2='luo' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
### @3='1' /* STRING(1) meta=65025 nullable=1 is_null=0 */
### @4='wer' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
### @5=3424924 /* INT meta=0 nullable=1 is_null=0 */
### @6=14248999 /* INT meta=0 nullable=1 is_null=0 */
### DELETE FROM `test`.`person`
### WHERE
### @1=3 /* INT meta=0 nullable=0 is_null=0 */
### @2='yu' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
### @3='0' /* STRING(1) meta=65025 nullable=1 is_null=0 */
### @4='jegu' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
### @5=7284474 /* INT meta=0 nullable=1 is_null=0 */
### @6=18949943 /* INT meta=0 nullable=1 is_null=0 */
### DELETE FROM `test`.`person`
### WHERE
### @1=4 /* INT meta=0 nullable=0 is_null=0 */
### @2='da' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
### @3='0' /* STRING(1) meta=65025 nullable=1 is_null=0 */
### @4='beijing' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
### @5=5244474 /* INT meta=0 nullable=1 is_null=0 */
### @6=4249943 /* INT meta=0 nullable=1 is_null=0 */
### DELETE FROM `test`.`person`
### WHERE
### @1=5 /* INT meta=0 nullable=0 is_null=0 */
### @2='gj' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
### @3='0' /* STRING(1) meta=65025 nullable=1 is_null=0 */
### @4='beijing' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
### @5=5244434 /* INT meta=0 nullable=1 is_null=0 */
### @6=13559943 /* INT meta=0 nullable=1 is_null=0 */
### DELETE FROM `test`.`person`
### WHERE
### @1=6 /* INT meta=0 nullable=0 is_null=0 */
### @2='yang' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
### @3='0' /* STRING(1) meta=65025 nullable=1 is_null=0 */
### @4='nanjing' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
### @5=4984434 /* INT meta=0 nullable=1 is_null=0 */
### @6=178999943 /* INT meta=0 nullable=1 is_null=0 */
# at 435
#181104 15:18:37 server id 1 end_log_pos 466 CRC32 0xab85d971 Xid = 197
COMMIT/*!*/;
# at 466
#181104 15:19:38 server id 1 end_log_pos 538 CRC32 0x8b9e1093 Query thread_id=16 exec_time=0 error_code=0
SET TIMESTAMP=1541315978/*!*/;
BEGIN
/*!*/;
# at 538
#181104 15:19:38 server id 1 end_log_pos 598 CRC32 0xb1679f78 Table_map: `test`.`person` mapped to number 85
# at 598
#181104 15:19:38 server id 1 end_log_pos 656 CRC32 0xa5d7a2d6 Write_rows: table id 85 flags: STMT_END_F

  通过上面的命令可以比较方便地逐页寻找被删除的数据,我们应该要找到被删除的数据在binlog中的起始和终止位置点,例如上面的被删除数据的位置点在192和435之间,这样我们可以保证在这两个位置之间只有我们需要的待恢复的数据,而没有其他数据。

本次测试的数据量很小,如果一张表有数十万行数据被误删除,我们通过上面的方式找位置点是很费时间的。这时可以通过下面的两个命令锁定起始和终止位置:
确定起始位置点:

mysqlbinlog -vv --start-datetime='2018-11-04 15:18:00' on.000004| head -1000 |more

  确定终止位置点:

mysqlbinlog -vv --start-datetime='2018-11-04 15:18:00' --stop-datetime='2018-11-04 15:20:00' on.000004| tail -1000 |more

  我们只看binlog输出的前N行和后N行,来找到起始和终止位置,这样可以大大节省时间。

三、将binlog里的delete语句转化为insert语句
Binlog是二进制文件,我们可以先把待恢复数据导出为可阅读文本:

mysqlbinlog -vv --start-position=192 --stop-position=435 on.000004 |grep ^"###" >/tmp/bin_data

接下来就是处理/tmp/bin_data文本,将里面的delete语句转化为insert语句,可以通过下面的语句实现转化:

cat /tmp/bin_data | sed -n '/###/p' | sed 's/### //g;s/\/\*.*/,/g;s/DELETE FROM/INSERT INTO/g;s/WHERE/SELECT/g;' |sed -r 's/(@6.*),/\1;/g' | sed 's/@[1-9]=//g' | sed 's/@[1-9][0-9]=//g' >/tmp/person.sql

四、将insert语句导入数据库中
Delete语句误操作只会删除表数据,而表结构还在。所以我们可以直接将文本里的insert语句导入到数据库中,即可完成数据恢复:

mysql -h127.0.0.1 -P3306 -uroot -p123 < /tmp/person.sql

补充和总结:
1、以上操作只针对delete误操作有效,且binlog模式是行模式;如果是drop或者truncate语句造成的误操作,亦或者binlog不是row模式,在binlog文件里是找不到完整的被删除数据,这个时候可以考虑通过备份进行恢复;
2、如果在误操作很久之后才意识到数据被误删除,记不清误操作的大致时间,那么可以找到误操作所在的binlog文件,将binlog解析为可阅读文本形式,然后借助文本编辑命令找误操作位置,再恢复;如果这种方式很慢的话,可以考虑通过备份恢复,或者从别的环境中导出这张表的数据再导入到当前环境中;
3、Mysqlbinlog命令重要参数
-vv 将二进制转换为可阅读文本
--start-datetime 起始时间
--stop-datetime 终止时间
--start-position 起始位置
--stop-position 终止位置
--base64-output=decode-row 查看最底层DML语句数据模块,前提是数据库参数binlog_rows_query_log_events打开
4、熟悉linux的文本编辑命令,如grep、sed、awk等
5、虽然binlog2sql工具也可以快速解析binlog,生成回滚SQL,但只要清楚上面的命令和操作流程,恢复速度也不会比binlog2sql慢很多,更何况如果环境没有安装这个工具。

  1. [root@cos7-jiang mysql]# mysqlbinlog -vv --start-datetime='2018-11-04 15:18:00' on.000004|more
  2.  
    /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
  3.  
    /*!40019 SET @@session.max_insert_delayed_threads=0*/;
  4.  
    /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
  5.  
    DELIMITER /*!*/;
  6.  
    # at 4
  7.  
    #700101 8:00:00 server id 1 end_log_pos 120 CRC32 0x199f2da4 Start: binlog v 4, server v 5.6.42-log created 700101 8:00:
  8.  
    00
  9.  
    # Warning: this binlog is either in use or was not closed properly.
  10.  
    BINLOG '
  11.  
    AAAAAA8BAAAAdAAAAHgAAAABAAQANS42LjQyLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  12.  
    AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAXAAEGggAAAAICAgCAAAACgoKGRkAAaQt
  13.  
    nxk=
  14.  
    '/*!*/;
  15.  
    # at 120
  16.  
    #181104 15:18:37 server id 1 end_log_pos 192 CRC32 0x2224f8de Query thread_id=16 exec_time=0 error_code=0
  17.  
    SET TIMESTAMP=1541315917/*!*/;
  18.  
    SET @@session.pseudo_thread_id=16/*!*/;
  19.  
    SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
  20.  
    SET @@session.sql_mode=1075838976/*!*/;
  21.  
    SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
  22.  
    /*!\C latin1 *//*!*/;
  23.  
    SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/;
  24.  
    SET @@session.lc_time_names=0/*!*/;
  25.  
    SET @@session.collation_database=DEFAULT/*!*/;
  26.  
    BEGIN
  27.  
    /*!*/;
  28.  
    # at 192
  29.  
    #181104 15:18:37 server id 1 end_log_pos 252 CRC32 0x65fbbe3b Table_map: `test`.`person` mapped to number 85
  30.  
    # at 252
  31.  
    #181104 15:18:37 server id 1 end_log_pos 435 CRC32 0x005d1b39 Delete_rows: table id 85 flags: STMT_END_F
  32.  
     
  33.  
    BINLOG '
  34.  
    TZ3eWxMBAAAAPAAAAPwAAAAAAFUAAAAAAAEABHRlc3QABnBlcnNvbgAGAw/+DwMDBgoA/gEKAD47
  35.  
    vvtl
  36.  
    TZ3eWyABAAAAtwAAALMBAAAAAFUAAAAAAAEAAgAG/8ABAAAAAmppATEDd2VyqEA0AGpqyADAAgAA
  37.  
    AANsdW8BMQN3ZXKcQjQAJ2zZAMADAAAAAnl1ATAEamVndfombwA3JyEBwAQAAAACZGEBMAdiZWlq
  38.  
    aW5nOgZQAFfZQADABQAAAAJnagEwB2JlaWppbmcSBlAAh+jOAMAGAAAABHlhbmcBMAduYW5qaW5n
  39.  
    cg5MAIdSqwo5G10A
  40.  
    '/*!*/;
  41.  
    ### DELETE FROM `test`.`person`
  42.  
    ### WHERE
  43.  
    ### @1=1 /* INT meta=0 nullable=0 is_null=0 */
  44.  
    ### @2='ji' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
  45.  
    ### @3='1' /* STRING(1) meta=65025 nullable=1 is_null=0 */
  46.  
    ### @4='wer' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
  47.  
    ### @5=3424424 /* INT meta=0 nullable=1 is_null=0 */
  48.  
    ### @6=13134442 /* INT meta=0 nullable=1 is_null=0 */
  49.  
    ### DELETE FROM `test`.`person`
  50.  
    ### WHERE
  51.  
    ### @1=2 /* INT meta=0 nullable=0 is_null=0 */
  52.  
    ### @2='luo' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
  53.  
    ### @3='1' /* STRING(1) meta=65025 nullable=1 is_null=0 */
  54.  
    ### @4='wer' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
  55.  
    ### @5=3424924 /* INT meta=0 nullable=1 is_null=0 */
  56.  
    ### @6=14248999 /* INT meta=0 nullable=1 is_null=0 */
  57.  
    ### DELETE FROM `test`.`person`
  58.  
    ### WHERE
  59.  
    ### @1=3 /* INT meta=0 nullable=0 is_null=0 */
  60.  
    ### @2='yu' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
  61.  
    ### @3='0' /* STRING(1) meta=65025 nullable=1 is_null=0 */
  62.  
    ### @4='jegu' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
  63.  
    ### @5=7284474 /* INT meta=0 nullable=1 is_null=0 */
  64.  
    ### @6=18949943 /* INT meta=0 nullable=1 is_null=0 */
  65.  
    ### DELETE FROM `test`.`person`
  66.  
    ### WHERE
  67.  
    ### @1=4 /* INT meta=0 nullable=0 is_null=0 */
  68.  
    ### @2='da' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
  69.  
    ### @3='0' /* STRING(1) meta=65025 nullable=1 is_null=0 */
  70.  
    ### @4='beijing' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
  71.  
    ### @5=5244474 /* INT meta=0 nullable=1 is_null=0 */
  72.  
    ### @6=4249943 /* INT meta=0 nullable=1 is_null=0 */
  73.  
    ### DELETE FROM `test`.`person`
  74.  
    ### WHERE
  75.  
    ### @1=5 /* INT meta=0 nullable=0 is_null=0 */
  76.  
    ### @2='gj' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
  77.  
    ### @3='0' /* STRING(1) meta=65025 nullable=1 is_null=0 */
  78.  
    ### @4='beijing' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
  79.  
    ### @5=5244434 /* INT meta=0 nullable=1 is_null=0 */
  80.  
    ### @6=13559943 /* INT meta=0 nullable=1 is_null=0 */
  81.  
    ### DELETE FROM `test`.`person`
  82.  
    ### WHERE
  83.  
    ### @1=6 /* INT meta=0 nullable=0 is_null=0 */
  84.  
    ### @2='yang' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
  85.  
    ### @3='0' /* STRING(1) meta=65025 nullable=1 is_null=0 */
  86.  
    ### @4='nanjing' /* VARSTRING(10) meta=10 nullable=1 is_null=0 */
  87.  
    ### @5=4984434 /* INT meta=0 nullable=1 is_null=0 */
  88.  
    ### @6=178999943 /* INT meta=0 nullable=1 is_null=0 */
  89.  
    # at 435
  90.  
    #181104 15:18:37 server id 1 end_log_pos 466 CRC32 0xab85d971 Xid = 197
  91.  
    COMMIT/*!*/;
  92.  
    # at 466
  93.  
    #181104 15:19:38 server id 1 end_log_pos 538 CRC32 0x8b9e1093 Query thread_id=16 exec_time=0 error_code=0
  94.  
    SET TIMESTAMP=1541315978/*!*/;
  95.  
    BEGIN
  96.  
    /*!*/;
  97.  
    # at 538
  98.  
    #181104 15:19:38 server id 1 end_log_pos 598 CRC32 0xb1679f78 Table_map: `test`.`person` mapped to number 85
  99.  
    # at 598
  100.  
    #181104 15:19:38 server id 1 end_log_pos 656 CRC32 0xa5d7a2d6 Write_rows: table id 85 flags: STMT_END_F

MySQL的delete误操作的快速恢复方法的更多相关文章

  1. MySQL【Delete误操作】数据恢复【转】

    前言:      操作数据库时候难免会因为“大意”而误操作,需要快速恢复的话通过备份来恢复是不太可能的,因为需要还原和binlog差来恢复,等不了,很费时.这里先说明下因为Delete 操作的恢复方法 ...

  2. MySQL【Update误操作】回滚(转)

    前言:      继上一篇MySQL[Delete误操作]回滚之后,现在介绍下Update回滚,操作数据库时候难免会因为“大意”而误操作,需要快速恢复的话通过备份来恢复是不太可能的,因为需要还原和bi ...

  3. MySQL中truncate误操作后的数据恢复案例

    MySQL中truncate误操作后的数据恢复案例 这篇文章主要介绍了MySQL中truncate误操作后的数据恢复案例,主要是要从日志中定位到truncate操作的地方然后备份之前丢失的数据,需要的 ...

  4. SQLServer 2008以上误操作数据库恢复方法——日志尾部备份(转)

    问题: 经常看到有人误删数据,或者误操作,特别是update和delete的时候没有加where,然后就喊爹喊娘了.人非圣贤孰能无过,做错可以理解,但不能纵容,这个以后再说,现在先来解决问题. 遇到这 ...

  5. [转]SQLServer 2008以上误操作数据库恢复方法——日志尾部备份

    原文出处:http://blog.csdn.net/dba_huangzj/article/details/8491327 问题: 经常看到有人误删数据,或者误操作,特别是update和delete的 ...

  6. Mysql MGR架构误操作引发的问题处理

    [背景介绍] 故障方描述:一次用户刷权限的时候不小心把数据库用户表记录删掉了,执行之后发现不对后重建用户,杀掉进程后重新MGR启动报错. [报错信息] 2018-06-13T12:47:41.4055 ...

  7. SQLServer 2008以上误操作数据库恢复方法

    解决方法:       对于这类问题,主要是找回误操作之前的数据,在2008之前,有个很出名的工具Log Exploer,听说还挺好用的,这个网上大把教程,这里就不多说了.但是唯一遗憾的是,不支持20 ...

  8. SQL Server 2008以上误操作数据库恢复方法——日志尾部备份

    原文出处:http://blog.csdn.net/dba_huangzj/article/details/8491327 问题: 经常看到有人误删数据,或者误操作,特别是update和delete的 ...

  9. SQLServer 2008以上误操作数据库恢复方法—日志尾部备份

    原文出处:http://blog.csdn.net/dba_huangzj/article/details/8491327 问题: 经常看到有人误删数据,或者误操作,特别是update和delete的 ...

随机推荐

  1. SpringBoot(二十一)_使用xml

    springboot使用xml 虽然springboot不提倡用xml,但是我们有可能也是会用到的 代码示例 1.创建一个配置文件在resources下,如下图所示 2.设置配置类 @Configur ...

  2. 【JS】JS数组添加元素的三种方法

    1.push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度. 1).语法: arrayObject.push(newelement1,newelement2,....,newelement ...

  3. Linux 部署 nginx

    nginx搭建 1. 清除之前nginx环境 #查看nginx进程 ps -ef|grep nginx #找到nginx相对应的位置 whereis nginx #停止nginx服务 /usr/loc ...

  4. SpringMVC日期类型接收空值异常问题

    最近遇到SpringMVC写个controller类,传一个空串的字符类型过来,正常情况是会自动转成date类型的,因为数据表对应类类型就是date的 解决方法是在controller类的后面加个注解 ...

  5. python TKinter的主窗口运行程序完毕后,怎么让其自动关闭

    如题: 在pycharm 调试Tkinter程序的时候,关闭右上角的X 实际上并未退出进程,长期以往 再大的内存也会被耗尽. 一般就是下面的代码: """ from tk ...

  6. SEH hook 的一种方法

    Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html 技术学习来源:火哥(QQ:471194425) 该方法的一些原理暂 ...

  7. kfifo

    kfifo 的一些伪代码 kfifo_len() out = LOAD fifo->out smp_rmb() len = LOAD fifo->in - out kfifo_in() k ...

  8. oracle学习笔记(八)——结果集元数据ResultSetMetaData以及ResultSet转为对应的实体类框架

    介绍 可用于获取关于 ResultSet 对象中列的类型和属性信息的对象,在持久框层框架(如:mybatis, hibernate)中被广泛的应用. 常用方法 int getColumnCount() ...

  9. MySQL(8)---游标

    Mysql(8)-游标 上一遍博客写了有关存储过程的语法知识 Mysql(7)---存储过程 游标或许你在工作中很少用到,但用不到不代表不去了解它,但你真正需要它来解决问题的时候,再花时间去学习很可能 ...

  10. go-运算符

    算术运算符 ++,--只能放在变量后面,不能放在前面 独立使用 目的:更简洁 go语言不支持三元运算符 键盘输入 fmt.scanln 会在换行时扫描,所以最后一个条目必须换行或达到结束位置 fmt. ...