MySQL的delete誤操作的快速恢復方法


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM