PURGE BINARY LOGS 失效主因是长事务阻塞从库位点推进,导致对应binlog无法被标记为可清理;必须先定位并终止拖慢复制的长事务,再FLUSH LOGS滚动日志,最后执行PURGE。

长事务让 PURGE BINARY LOGS 命令失效
MySQL 的 PURGE BINARY LOGS 不是“删掉最老的 N 个文件”,而是“只删从库已确认读完的 binlog”。只要有一个从库还在读某个 binlog 文件(哪怕只差一个字节),该文件就绝不会被 PURGE 删除——而长事务正是让从库卡住的元凶。
常见现象:PURGE BINARY LOGS TO 'mysql-bin.000123'; 执行后 SHOW MASTER LOGS; 显示最老仍是 mysql-bin.000120,且磁盘持续增长。
- 长事务在主库上未提交,binlog 中对应事务的
COMMIT事件还没写入,从库的Exec_Master_Log_Pos就永远停在那个位置,无法推进 -
expire_logs_days = 7不会触发清理:它只在FLUSH LOGS或 MySQL 重启时检查,且同样受从库位点约束 - 即使手动
rm -f mysql-bin.000120,MySQL 启动时会因mysql-bin.index缺失报错退出
如何快速定位阻塞 Binlog 清理的长事务
别只看 INNODB_TRX 里的 trx_started 时间,重点查“谁在拖慢从库位点”。直接运行:
SELECT r.trx_id, r.trx_state, r.trx_started, r.trx_query, s.Slave_IO_State, s.Master_Host, s.Exec_Master_Log_Pos, s.Relay_Master_Log_File FROM information_schema.INNODB_TRX r JOIN performance_schema.replication_connection_status s ON 1=1 WHERE r.trx_state = 'RUNNING' AND UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(r.trx_started) > 300;
再比对 SHOW MASTER LOGS; 最老文件的 File_size 和 s.Relay_Master_Log_File 是否一致。若不一致,说明该从库正卡在旧 binlog 上——而卡点往往就是长事务的 COMMIT 之前。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
长事务 + ROW 格式 = Binlog 爆炸性膨胀
ROW 格式的 binlog 不记 SQL,而记每一行变更的完整镜像。一个长事务更新 50 万行,所有中间状态都缓存在内存并最终写入 binlog —— 这不是“一条大日志”,而是 50 万条独立事件,且事务不提交就不落盘,全压在 binlog_cache_size 和磁盘临时缓冲区里。
-
binlog_format = ROW且binlog_row_image = FULL(默认)时,UPDATE 会记录 before/after 两份快照,体积翻倍 - 长事务期间若发生主库 crash,未刷盘的 binlog 缓存丢失,但从库可能已部分重放,造成主从数据不一致
-
max_binlog_cache_size默认 4G,但单个长事务超限时会直接报错ERROR 1197 (HY000): Multi-statement transaction required more than 'max_binlog_cache_size' bytes
真正有效的清理动作顺序
不能先 PURGE,也不能先 KILL——顺序错了反而加重磁盘压力。必须按这个链路操作:
- 用
df -h /var/lib/mysql确认是否真爆满(Use% ≥ 95%);如果不是,问题不在磁盘,而在复制延迟本身 - 查
SHOW SLAVE STATUS\G中的Seconds_Behind_Master和Exec_Master_Log_Pos,确认从库是否真的卡住 - 在主库执行
SELECT * FROM information_schema.INNODB_TRX WHERE trx_state = 'RUNNING' AND trx_started ,人工判断哪些事务可杀(注意:trx_query IS NULL且线程在SHOW PROCESSLIST中为Sleep才是高危对象) - KILL 后等待 30 秒,再立刻执行
FLUSH LOGS,强制滚动新 binlog,让旧文件进入可 PURGE 状态 - 最后执行
PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 1 HOUR);(比expire_logs_days更可控)
最容易被忽略的是:PURGE 操作本身会写新的 binlog 事件(Rotate_log_event),如果磁盘只剩几十 MB,这一步可能直接失败。务必确保清理前留出至少 200MB 安全空间。










