誤刪數據的幾種操作
- 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點誤刪除了一個庫里的某張表,恢復數據的流程如下:
- 取最近的一次全量備份,假設該庫是一天一備,上次備份時間就是當天0點
- 用備份恢復出一個臨時庫
- 從日志備份里取出0點以后的日志
- 把這些日志,除了誤刪除數據的語句外,全部應用到臨時庫
- 為了加速數據恢復,如果這個臨時庫上有多個數據庫,在使用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自動化平臺),并大量測試后進行使用,避免手動誤操作帶來更大的問題。
一般的主備復制存在的問題是,假設主庫上的表被刪除,這個命令很快會被發給所有從庫,進而導致從庫的數據表也被一起誤刪除。
延遲復制備庫是可以持續保持與主庫有N秒延遲的備庫。
CHANGE MASTER TO MASTER_DELAY=N;
假設這里N=3600,那么表示只要在1個小時以內發現了誤刪除,就可以的到備庫上執行stop slave,再通過之前講到的方法,跳過誤操作的命令(比如將誤刪除的GTID加到實例集合中),就可以恢復出需要的數據。
rm誤刪
只要你的集群是高可用,如果rm刪除了某個節點(只要不是惡意刪除所有節點),HA系統會自動開始工作,選出一個新的主庫,從而保證集群工作。