bigywater.tech
MySQL / InnoDB · 27

binlog 与 GTID:当前实例到底记录了什么

查看binlog和GTID的当前状态,验证一条事务后GTID计数器精确加1,再用SHOW BINLOG EVENTS看ROW格式binlog记录的事件结构。

1-143→1-144
一次事务后GTID精确的变化
SHOW BINARY LOG STATUS
替代旧版SHOW MASTER STATUS的新命令
Table_map+Write_rows
ROW格式binlog的事件结构

做的事:查当前实例记录到了哪里

binlog是MySQL记录"发生了什么改动"的日志,GTID是给每个事务分配的全局唯一编号。

结果SHOW VARIABLES LIKE 'log_bin' → ON SHOW VARIABLES LIKE 'gtid_mode' → ON SHOW VARIABLES LIKE 'binlog_format' → ROW SHOW BINARY LOG STATUS → File: binlog.000002 → Position: 73487330 → Executed_Gtid_Set: efd7431a-b8ac-11f1-be90-82c03ef30a57:1-143

一个小发现:老版本教程里常见的 SHOW MASTER STATUS,在这个版本已经改名成了 SHOW BINARY LOG STATUS(语法报错验证过,旧写法在这个版本压根不认)。

验证:一条事务,GTID计数器精确加1

GTID的格式是"server-uuid:序号范围",每个事务都会拿到一个新序号。

结果执行前: efd7431a-b8ac-11f1-be90-82c03ef30a57:1-143 INSERT INTO t10 (email) VALUES ('gtid-test@x.com'); 执行后: efd7431a-b8ac-11f1-be90-82c03ef30a57:1-144

一条的INSERT语句,GTID区间从1-143精确变成了1-144——每一个提交的事务,不管改了多少行,都会拿到唯一的一个GTID编号,这个编号全局唯一(前缀是这台server的UUID),在主从复制场景里,靠比较GTID集合就能精确判断某个事务有没有被执行过,不需要靠binlog文件名+偏移量这种脆弱的定位方式。

验证:ROW格式下,一次批量插入拆成了多条事件

binlog_format=ROW意味着记录的是每一行数据的变化,不是SQL语句本身。

结果(SHOW BINLOG EVENTS片段)Table_map table_id: 86 (demo.t1) Write_rows table_id: 86 flags: USE_SQL_FOREIGN_KEY_F Write_rows table_id: 86 flags: USE_SQL_FOREIGN_KEY_F Write_rows table_id: 86 flags: USE_SQL_FOREIGN_KEY_F ...(连续多条Write_rows事件)
看到的是:一次批量INSERT(本文早前一次性插入10万行的操作)在binlog里不是一条"INSERT INTO ... VALUES (...)"的SQL文本,而是先有一条 Table_map 事件(说明接下来的数据行属于哪张表),后面跟着一串 Write_rows 事件,每条携带一批实际写入的行数据(受 binlog_row_event_max_size 限制,太大的一批会被拆成多个事件)。这就是ROW格式binlog的样子:记录的是数据本身的变化,而不是产生这个变化的SQL语句——这也是为什么ROW格式复制比老式的STATEMENT格式更可靠:不管原始SQL里有没有用到不确定函数(如NOW()、RAND()),复制到从库时执行的都是完全一致的具体数据行,不会出现主从结果不一致的问题。

分步演示:binlog和GTID记录了什么

每一步都是本文上面用MySQL跑出来的原始结果。

每个事务拿到唯一的GTID,binlog记录的是数据不是SQL
这一步新验证的结果

    本文用到的工具

    • 本机 MySQL 26.7.0(InnoDB),log_bin+gtid_mode均开启
    • SHOW BINARY LOG STATUS / SHOW BINLOG EVENTS:查看binlog与GTID状态
    京ICP备2026067502号-1京公网安备11010502063487号