31-误删数据后除了跑路,还能怎么办?
# 误删行
通过 flashback 工具可以恢复,但是有前提。
- binlog_format=row:这是 MySQL 中二进制日志的格式设置。'row' 表示以行级别的形式进行二进制日志记录。在此模式下,对数据库的每一行变更(插入、删除、更新)都会被记录在日志中。因此,'row' 模式可以提供更详细的日志,但也可能导致日志文件较大。
- binlog_row_image=FULL:这是在 'redo log' 中记录的信息级别。'FULL' 表示在重做日志中完整记录每一行的所有数据。也就是说,不仅会记录所更改的字段,还会记录那一行的所有数据。因此,这种设置可以提供最详细的日志信息,但同样也可能导致日志文件较大。
但是不建议在主库上执行,如果有其他线程在误删的基础上做操作的话,如果恢复了数据,可能会出现二次破坏。
所以建议在设置的时候把 sql_safe_updates=on 配置上,就是说如果在 update 和 delete 中没有 where 条件,就不能执行。但是说如果真的需要删除全部数据。
用 delete from t where id > 0
,但是这样删除是很慢的,需要写 undo log redo log binlog。如果有时间上的限制,还是使用 truncate/drop table 和 drop database 命令删除。
但是这样就无法使用 flashback 来恢复了,因为无论 binlog 是什么格式的都只会记住一个 truncate
或者 drop
命令,是无法恢复的。
# 误删库 / 表
这种情况下必须有全量的 binlog 日志,否则无法恢复。
步骤是
- 比如每天 0 点一备份,先把 0 点之前的所有数据恢复到一个临时库。
- 再取出 0 点后的日志,去掉误删的语句后,再恢复到临时库。
- 跳过误删的 binlog 有两种方法:
- 如果没有启用 GTID 模式,在有记录误删的 binlog 中先用 - stop-position 参数执行到误删之前的日志,然后再用 - start-position 参数执行误删之后的日志。
- 如果启用了 GTID 模式,假设误删的命令的 GTID 是 gtid1, 执行
set gtid_next=gtid1;begin;commit;
, 先把这个 GTID 加到临时的 GTID 集合中,之后执行 binlog 的时候就会自动跳过了。
- 跳过误删的 binlog 有两种方法:
但是中间需要考虑的是执行速度的问题,这块内容看原文。
# 延迟复制备库
如果一个备库的非常大,或者误操作的时间距离上次备份时间较长如一周一备份,在备份之后的第 6 天发生误操作,那就需要恢复 6 天的日志,这个恢复时间可能是要按天来计算的。
像这样的业务恢复需要很长时间,建议通过搭建延迟复制的备库。用一个备库连接主库然后使用 CHANGE MASTER TO MASTER_DELAY = N
指定这个备库和主库有多少秒延迟。
一旦误删,赶紧再备库上执行 stop slave 命令。如果延迟只有 1 小时只用恢复 1 小时的数据即可。
# 预防误删库 / 表
- 账号分离,只给开发人员 DML 的权利,不给 DDL 以及 truncate/drop。
- 在监督下操作删除命令。
# rm 删除
如果有 HA 的话可以选举一个新的主库,然后赶紧恢复数据到一个新的实例,再接入整个 HA 即可。
如果删除的是 HA 整个集群的话,赶紧跑路吧。
# 上一章答案
begin;
select * from t where id>1 for update;
2
如果说这个表是空表,锁的范围是?
上面的查询语句锁是 next-key lock (-∞, supremum]。