mysql.gtid_executed表、gtid_executed变量、gtid_purged变量的修改时机
1.2 mysql.gtid_executed表、gtid_executed变量、gtid_purged变量的修改时机
1.2.1 定义
-
mysql.gtid_executed表:GTID持久化的介质,GTID模块初始化的时候会读取这个表作为获取gtid_executed变量的基础。
-
gtid_executed变量:表示数据库中执行了哪些GTID,它是一个处于内存中的GTID SET。show slave status中的Executed_Gtid_Set和show master status中的Executed_Gtid_Set都来自它。
mysql> show master status\G
*************************** 1. row ***************************
File: binlog.000001
Position: 4083
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: ff3a5c20-abbe-11ef-88a4-fa163e176c3c:1-15
1 row in set (0.01 sec)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for source to send event
Master_Host: 127.0.0.1
Master_User: root
Master_Port: 3307
Connect_Retry: 60
...
Retrieved_Gtid_Set: ff3a5c20-abbe-11ef-88a4-fa163e176c3c:1-15
Executed_Gtid_Set: ff3a5c20-abbe-11ef-88a4-fa163e176c3c:1-15
...
Network_Namespace:
1 row in set, 1 warning (0.00 sec)
-
gtid_purged变量:表示由于删除binary log(如执行purge binary logfiles命令或者超过参数expire_logs_days设置),已经丢失的GTID Event,它是一个处于内存中的GTID SET。我们在搭建从库时,通常需要使用set global gtid_purged命令设置本变量,用于表示这个备份已经执行了哪些GTID操作。需要注意的是,手动删除binary log不会更新这个变量。(即这些GTID对应的事务已经执行并确认)
其中,gtid_executed变量和gtid_purged变量都是通过show global variables命令来获取的。这也是数据库管理员通常能够观察到的几种GTID 信息,有了前文的描述,我们知道其中的mysql.gtid_executed表是一种GTID持久化的介质,gtid_executed变量和gtid_purged变量则对应了内部结构体Gtid_state中的executed_gtids和lost_gtids内存数据,它们分别表示数据库执行了哪些GTID操作,又有哪些GTID操作由于删除binary log已经丢失了。
注意:gtid_executed变量一定是实时更新的,不管是主库还是从库。
下图中灰色部分为常见配置:
1.2.2 主库修改时机
binary log关闭
在binary log关闭的状态下,不生成GTID,mysql.gtid_executed表、gtid_executed变量、gtid_purged变量均不更新。
binary log打开
主库通常都被设置成binary log打开的状态,需要重点关注一下。
mysql.gtid_executed表修改时机
mysql.gtid_executed表一直保存上一个binary log执行过的全部GTID,直到binary log切换(当前日志文件已满或达到了切换点,决定创建一个新的binlog文件)时才会被更新,即不是每执行一个事务就实时更新。
这个过程主要会调用Gtid_state::save_gtids_of_last_binlog_into_table函数,下面是部分代码:
gtid_executed变量修改时机
在事务commit的FLUSH阶段生成GTID,在COMMIT阶段才计入gtid_executed变量,它是实时更新的。这个过程是通过调用Gtid_state::update_gtids_impl函数完成的。代码如下。

注意:上述涉及到的两个阶段?
-
在事务提交过程中,有一个FLUSH阶段。在这个阶段,MySQL会确保所有与该事务相关的更改都已经写入到binlog日志中,并且这些更改对于其他事务来说是可见的(或是不可见的,但至少已准备好在后续阶段中变得可见)。在这个FLUSH阶段,MySQL会为当前事务生成一个唯一的GTID。
-
在事务提交的COMMIT阶段,MySQL会将之前FLUSH阶段生成的GTID添加到gtid_executed变量中。这意味着,一旦事务提交成功,其GTID就会被记录在gtid_executed变量中,从而表明该事务已经被执行。
gtid_purged变量修改时机
在清理binary log时修改,比如在执行命令purge binary logs或者超过参数expire_logs_days的设置后自动删除,需要将丢失的GTID SET计入这个变量,因此它不是实时更新的。这个过程主要集中在MYSQL_BIN_LOG::purge_logs函数中。代码片段如下。
1.2.3 从库修改时机
binary log开启,参数log_slave_updates关闭
通常,从库都被设置为这种状态,需要重点关注一下。
mysql.gtid_executed表修改时机
前面已经说过,在这种情况下从库没有办法通过binary log来持久化执行过的GTID事务,因为它根本就没有记录Event。只能通过实时更新mysql.gtid_executed表来保存,所以必须要实时将GTID持久化到mysql.gtid_executed表中。其主要逻辑包含在commit_owned_gtids函数中。代码片段如下。
gtid_executed变量修改时机
实时更新,但是更新位置和主库不同,因为这里不会执行 order commit 步骤了。由Gtid_state::update_on_commit函数调入。
gtid_purged变量修改时机
因为没有binary log来记录已经执删除的GTID Event,所以gtid_purged变量实时更新。其处理逻辑依然是通过Gtid_state::update_on_commit函数调入Gtid_state::update_gtids_impl_own_gtid函数进行的。代码片段如下。
binary log开启,参数log_slave_updates开启
在这种情况下,SQL 线程执行过的GTID操作可以通过 binary log 进行保存,所以mysql.gtid_executed表和gtid_purged变量不需要实时更新。
mysql.gtid_executed表修改时机
和主库一致。即在日志切换时更新,不做讨论。
gtid_executed变量修改时机
和主库一致,实时更新,不做讨论。
gtid_purged变量修改时机
和主库一致,在binary log删除时更新,不做讨论。
1.2.4 通用修改时机
mysql.gtid_executed表修改时机
在执行reset master命令时清空本表:其主要逻辑在Gtid_state::clear函数中。
在执行set global gitd_purged命令时设置本表:其主要逻辑在Gtid_state::add_lost_gtids函数中。
gtid_executed变量修改时机
在执行reset master命令时清空本变量:其主要逻辑在Gtid_state::clear函数中。
在执行set global gitd_executed命令时设置本变量:其主要逻辑在Gtid_state::add_lost_gtids函数中。
在mysql启动时初始化设置gtid_executed变量:GTID模块的初始化将在1.3节介绍。
gtid_purged变量修改时机
在执行reset master命令时清空本变量:其主要逻辑在Gtid_state::clear函数中。
在执行set global gitd_purged命令时设置本变量:其主要逻辑在Gtid_state::add_lost_gtids函数中。
在MySQL启动时初始化gtid_purged变量。
1.2.5 通用修改时机源码函数简析
我们来看1.2.4节提到的两个接口。
Gtid_state::clear函数逻辑
Gtid_state::add_lost_gtids函数逻辑