必须同时满足log_bin=on且binlog_format=row,否则无法精准定位误删行;通过mysqlbinlog解析delete_rows_event并结合user_host等上下文可追溯执行来源。

确认是否开启了 binlog 且格式为 ROW
被删数据的 SQL 执行来源能否追溯,第一道门槛就是 binlog 是否开启、格式是否为 ROW。如果 log_bin 是 OFF,或 binlog_format 是 STATEMENT,那几乎无法定位到具体哪条 DELETE 语句删了哪行——因为后者只记录原始 SQL 文本,不记录实际影响的行;前者则根本没日志。
执行以下命令验证:
SHOW VARIABLES LIKE 'log_bin';<br>SHOW VARIABLES LIKE 'binlog_format';
必须同时满足:log_bin = ON 且 binlog_format = ROW。注意:MIXED 模式下,MySQL 可能自动降级为 STATEMENT,不可靠,应显式设为 ROW。
用 mysqlbinlog 解析并定位删除操作
mysqlbinlog 是唯一能从二进制日志里还原“谁在什么时间删了哪条记录”的命令行工具。关键在于:它能解析出 DELETE_ROWS_EVENT,并附带 @1=xxx, @2=yyy 这样的字段值快照,以及 SET @@SESSION.PID 和 SET @@session.user_host(MySQL 5.7+)这类上下文信息。
操作步骤如下:
- 先查出删操作大概发生的时间段,再用
SHOW BINLOG EVENTS IN 'binlog.0000xx' FROM N LIMIT 100快速扫一遍事件,找到Delete_rows类型事件及其Pos - 用完整命令解析(务必加
--base64-output=DECODE-ROWS -v):mysqlbinlog --no-defaults --base64-output=DECODE-ROWS -v --start-position=123456789 --stop-position=123457890 /var/lib/mysql/binlog.0000xx - 在输出中搜索
### DELETE FROM `db`.`table`,其上方通常有SET @@session.user_host='user@host'或SET @@session.sql_log_bin=0等标记,这就是执行来源线索
performance_schema.events_statements_history_long 能查到吗?
不能直接用于“事后追查”。这个表只保留最近执行过的语句(默认最多 10000 行),且内容是内存中的历史快照,数据库重启即清空。如果你在删操作发生前就已开启相关 consumer,并且该语句尚未被轮替掉,才可能查到:
SELECT THREAD_ID, USER, HOST, SQL_TEXT, EVENT_TIME<br>FROM performance_schema.events_statements_history_long<br>WHERE SQL_TEXT LIKE '%DELETE%table_name%' AND EVENT_TIME > '2026-09-29 14:00:00'<br>ORDER BY EVENT_TIME DESC LIMIT 5;
但要注意:THREAD_ID 对应的是会话 ID,不是操作系统 PID;USER 和 HOST 字段只有在连接时未被代理或中间件覆盖时才可信;而且该表不记录参数化值,仅存文本,无法确认是否真删了目标行。
为什么通用查询日志(general_log)很少被用作追踪依据
虽然 general_log 会记录所有语句(含 DELETE)和客户端 IP/用户,但它有三个硬伤:
- 性能开销极大,生产环境基本禁用;临时开启后,日志里只有
DELETE FROM t WHERE id=123这种文本,没有执行时间戳精度、事务上下文、影响行数等关键信息 - 日志文件是纯文本,无法按结构化方式关联线程、事务 ID 或锁等待链
- 如果语句来自应用层拼接(如 ORM 的批量删除),
general_log里看到的往往是带占位符或变量名的语句,甚至被预编译隐藏,难以对应真实数据
真正可靠的来源永远是 binlog(ROW 格式)+ 时间窗口 + mysqlbinlog 解析。其他手段要么不可靠,要么依赖事前配置,且恢复链条更长。











