gtid集合不一致本身不是异常,而是复制延迟或中断的自然表现;真正需警惕的是executed_gtid_set持续停滞或retrieved_gtid_set与主库executed_gtid_set完全脱节。

GTID集合不一致不是“异常状态”,而是复制延迟或中断后的自然表现;真正要警惕的是 Executed_Gtid_Set 持续停滞、或 Retrieved_Gtid_Set 与主库 Executed_Gtid_Set 完全脱节。
怎么看主从 GTID 集合差异?
先别急着修,得看清差在哪。主库只看 SHOW MASTER STATUS 的 Executed_Gtid_Set;从库必须同时看两个字段:
-
Retrieved_Gtid_Set:已拉到 relay log 但还没执行的 GTID(说明 IO 线程正常) -
Executed_Gtid_Set:实际已提交的事务 GTID(反映 SQL 线程进度)
常见现象:Retrieved_Gtid_Set 和主库一致,但 Executed_Gtid_Set 少一截 → SQL 线程卡住;Retrieved_Gtid_Set 停滞不动 → IO 线程断连或权限/网络问题。
为什么 Executed_Gtid_Set 会漏掉事务?
根本原因不是 GTID 本身出错,而是事务没成功执行。典型场景包括:
- 从库表结构缺失或字段类型不兼容(比如主库
VARCHAR(255),从库是TEXT,某些隐式转换失败) - 遇到
ERROR 1032(找不到记录)或ERROR 1062(唯一键冲突),SQL 线程直接报错停止 - 从库开启了
read_only=ON,但误操作写了临时表或系统表(如mysql.user),导致后续 GTID 执行被跳过 - 主库用了
CREATE TEMPORARY TABLE或MEMORY表,这类语句不记 binlog,但从库若手动建了同名表,后续 DML 就可能错乱
gtid_purged 被意外修改会怎样?
这是最隐蔽也最危险的操作。如果在从库执行过 RESET MASTER,或手动设置了 gtid_purged,会导致从库“宣称”自己已执行过一批它根本没跑过的事务。
后果很直接:CHANGE MASTER TO ... MASTER_AUTO_POSITION = 1 时,主库按从库声明的 gtid_purged 发送 binlog,跳过那部分事务 —— 数据永久丢失,且 SHOW SLAVE STATUS 看不出异常。
验证方式:对比从库的 SELECT @@global.gtid_purged 和主库的 SELECT @@global.gtid_executed,前者不能包含后者没有的 UUID:NUMBER 段。
跳过错误 GTID 的风险在哪?
用 SET GTID_NEXT + 空事务“补位”看似能对齐集合,但前提是你知道那个 GTID 对应的事务完全可丢弃。
- 如果该 GTID 是一条
UPDATE,跳过等于丢数据 - 如果该 GTID 是一个 DDL(比如
ALTER TABLE),跳过会导致后续 DML 因表结构不匹配而持续失败 - MySQL 8.0.23+ 对空事务跳过做了限制,
SET GTID_NEXT后必须显式BEGIN; COMMIT;,否则报错
真正安全的做法是:先用 pt-table-checksum 定位不一致的表,再用 pt-table-sync 修复,而不是靠 GTID 集合“看起来一样”来判断数据一致。
GTID 集合对不上,往往只是表象;背后可能是表结构漂移、人为写入、或一次未察觉的复制中断。盯住 Seconds_Behind_Master 和 Slave_SQL_Running_State 比盯着集合数字更有意义。











