先抛个问题:如果你的生产库某张表几千行数据在一个小时内被静默改掉了,你拿什么去追责、反查、恢复?很多人第一反应是看应用日志、看操作日志,但真正靠谱的答案其实是 MySQL 自己写下的那堆二进制日志——binlog。这个东西平时躺在数据目录里不起眼,等出了事才发现它比什么备份都金贵。这篇文章就围绕 mysql 查看 binlog 日志这件事,把 binlog 的原理、开启方式、查看命令、实战反查和恢复流程一次性讲透。
这篇文章适合所有维护 MySQL、或者工作中要对接 MySQL 的开发、运维、DBA,包括刚入门不久、被线上问题逼着去翻 binlog 的同学。不用急着背命令,先搞懂 binlog 到底记了什么,再上手操作,你会发现它其实就是数据库留给你的一本“流水账”,会读账本之后,误删恢复、主从排查、数据同步问题都会顺手很多。
1. binlog到底是什么:一个数据库“黑匣子”的自我修养
1.1 光靠binlog可不够:redo log、undo log和它的分工
很多刚学 MySQL 的人会把日志混为一谈,其实 InnoDB 引擎和 MySQL Server 层各写各的日志,核心就是三类:redo log、undo log、binlog。
redo log 是 InnoDB 引擎层的物理日志,记录的是“某个数据页被改成了什么样”,它是循环写的,磁盘上就那么几个文件,写完就覆盖。它的使命是保证崩溃恢复——数据库突然断电,内存里还没落盘的数据靠 redo log 重放,不会丢。注意,redo log 只关心崩溃那一刻的数据安全,不关心你历史上执行过哪些 SQL。
undo log 也是 InnoDB 层的,记录的是“改之前的数据长什么样”,用来支持事务回滚和 MVCC 多版本控制。你回滚一条 UPDATE,本质上就是拿 undo log 里的旧值把数据覆盖回去。但 undo log 是事务级的临时记录,事务一提交,历史版本就可能被清理掉,所以它也不适合做长期审计和恢复。
binlog 则是 Server 层的东西,和具体存储引擎无关。它记录的是数据库“发生了哪些逻辑变更”,是追加写,一个文件写满就换下一个,不会主动覆盖。只要你不手动清理,它会一直留着。它的价值可以概括成三个词:恢复、复制、审计。主从复制是靠它把主库的变更同步给从库;误删数据后可以用它把数据库回滚到某个时间点;出了安全事故时,可以用它追查到底是谁在什么时候改了哪条数据。
打个比方:redo log 是会计的草稿纸,画错了涂掉重来,只保证账目最终正确;binlog 是监控录像,一帧一帧记录着谁动了哪笔账,你随时可以回放查证。
1.2 binlog到底记了什么:从一条UPDATE说起
要理解 binlog 能查什么,先得知道它记录的内容形态。拿一条最简单的 UPDATE 举例:
sql复制UPDATE user SET age = 20 WHERE id = 1;
binlog 有几种记录格式,最常见的是 STATEMENT 和 ROW,后面会详细对比。在 STATEMENT 格式下,binlog 里直接记下这条 SQL 文本,主从复制时从库原样执行一遍。在 ROW 格式下,binlog 不记 SQL 文本,而是记“哪张表的哪一行发生了变化,旧值是什么、新值是什么”。对上面的 UPDATE,ROW 格式会记录 id=1 这一行的 age 从旧值变成了 20,还会记录其它列的完整值。
所以查询类语句如 SELECT、SHOW 是不会出现在 binlog 里的,这和你直觉里“日志就该记录所有操作”不太一样。如果你真想审计谁查了哪些数据,那得开通用查询日志 general_log,但那个日志线上一般不开,因为性能消耗大、文件膨胀快,而且记录的是客户端发过来的原始请求,量非常大。binlog 只在数据发生变更时才有存在感:INSERT、UPDATE、DELETE、DDL(CREATE TABLE、ALTER TABLE、DROP TABLE 等)都会记。
还有一个容易忽略的点:binlog 记录了事件发生的时间戳、执行事务的 server-id、事务的 GTID(如果开启了 GTID)、起始位置(position)等元信息。这些元信息是后面做精准定位的关键——你不仅能知道“改没改”,还能定位“在哪个日志文件、哪个偏移量开始的”。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动手前先看两件事:binlog开没开、什么格式在写
2.1 三个命令确认当前状态
很多人查 binlog 时发现 SHOW BINARY LOGS 查不到任何文件,或者 mysqlbinlog 解析出来全是乱码,第一步就卡住了,原因往往是 binlog 根本没开,或者格式不对。上生产环境前,先用这三个命令摸清家底:
sql复制SHOW VARIABLES LIKE 'log_bin';
SHOW VARIABLES LIKE 'binlog_format';
SHOW BINARY LOGS;
log_bin 只有两个值 ON 或 OFF。如果是 OFF,下面所有操作都免谈,得先改配置开启。binlog_format 显示当前 binlog 的写入格式,常见值是 ROW、STATEMENT、MIXED。SHOW BINARY LOGS 会列出当前实例已经产生的所有 binlog 文件名和文件大小。
还有一个隐藏命令也很有用:
sql复制SHOW MASTER STATUS;
它返回当前正在写入的 binlog 文件名和当前写入位置(Position)。做全量备份、增量恢复时,这个值就是你的“水位线”——备份做到哪了、后续要从哪个位置开始补 binlog。
2.2 binlog_format三种模式怎么选
binlog_format 决定了 binlog 记录内容的粒度,这是很多实战问题的根源之一。三种模式对比如下:
| 格式 | 记录内容 | 优点 | 缺点 |
|---|---|---|---|
| STATEMENT | 原始 SQL 文本 | 日志量小,易读 | 不确定函数(NOW()、UUID())在主从执行结果可能不一致 |
| ROW | 具体行的变化前后值 | 主从绝对一致,恢复精准 | 日志量大,可读性差,需要用工具解析 |
| MIXED | 默认记 SQL,遇到不确定操作自动切 ROW | 折中方案 | 定位问题时行为不可预期,会有混搭情况 |
生产环境我的建议是直接 ROW。原因很简单:主从复制一致性最可靠,误删恢复时也能拿到完整旧值。STATEMENT 格式虽然日志小,但一条 DELETE FROM t WHERE id > 100 在 STATEMENT 格式下只记录一句 SQL,而 ROW 格式会记录删除的每一行旧数据。真要恢复时,后者能让你精确知道删了哪些数据、原值是什么;前者只能告诉你“执行过这么一条 SQL
