深入理解MySQL主从原理
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.4 重点Event之QUERY_EVENT和MAP_EVENT

2.4.1 QUERY_EVENT

1.QUERY_EVENT的作用

QUERY_EVENT不仅会记录一些语句的运行环境,比如SQL_MODE、客户端字符集、自增环境设置、当前登录数据库等,而且会记录执行时间。但对于行模式的 DDL 和 DML 记录的执行时间会有所不同,需要额外注意,如下。

DML:执行时间记录的是第一条数据更改后的时间,而不是DML语句执行的时间(一个DML语句可能修改很多条数据)。这个时间往往非常短,不能正确地表示DML语句执行的时间。语句部分记录的是begin。

DDL:执行时间记录的是实际语句的执行时间,语句部分记录的是实际的语句。

执行时间是 Seconds_Behind_Master 计算的一个影响因素,4.9 节将会详细介绍Seconds_Behind_Master的计算公式。一个事务只有一个QUERY_EVENT。

2.源码重要接口

主库

· 初始化构造函数:Query_log_event::Query_log_event(THD* ,char const* ,size_t,bool,bool,bool,int,bool);

· 写入binlog cache:Query_log_event::write(IO_CACHE* file)。

从库

· 读取构造函数:Query_log_event::Query_log_event(char const*,uint,binary_log::Format_description_event const* ,binary_log::Log_event_type);

· 应用函数:Query_log_event::do_apply_event。

3.主体格式

QUERY_EVENT包含固定和可变两部分,如图2-5所示。

图2-5

其中,固定部分如下。

slave_proxy_id:4字节,主库生成Event的thread id,它和show processlist中的id对应。

query_exec_time:4字节,这是执行时间。但是对于行模式的 DML 语句,这个执行时间并不准确,上面已经描述了原因。而对于DDL,它还是比较准确的。

db_len:1字节,用于描述数据库名的长度。

error_code:2字节,执行语句的错误码。

status_vars_len:2字节,status variables部分的长度。

可变部分如下。

status variables:环境参数,其中包含很多种格式。每种格式都有自己的长度和数据域,因此可以轻松地读取到各种值。比如SQL_MODE、客户端字符集、自增环境、客户端排序字符集等,但是其过于复杂,这里不做解析。

db:当前登录的database名字,以0x00结尾。主库来源为源码变量thd->db。如果是语句模式,则从库做过滤的时候会使用这个名字。

query:具体的语句。对于行模式的DML,记录的是begin,而对于DDL,记录的是具体的语句。

如果我们打开Query_log_event::do_apply_event函数,就会看到,这个Event在从库应用的时候会设置各种环境,比如客户端字符集、自增环境设置、当前登录数据库等,然后执行相应的语句,而对于行模式的DML,这里只会执行begin。注意一个细节,其中包含一段代码:

这段代码会设置线程的命令执行时间为Event header中Timestamp的时间,因此,我们在从库上执行now()函数时,是可以得到正确的结果的。

4.实例解析

下面是一个行模式的DML的QUERY_EVENT(mysqlbinlog--hexdump输出):

其中,固定部分如下。

06 00 00 00:thread id为6。

00 00 00 00:执行时间,对于行模式的DML来讲通常不准。

04:当前登录数据库名的长度。

00 00:错误码。

1a 00:status variables部分的长度,十六进制值1a就是十进制值26。

可变部分如下。

status variables:略。

74 65 73 74 00:当前登录库名test的ASCII编码,以0x00结尾。

42 45 47 49 4e:语句BEGIN的ASCII编码。

中间有一部分是status variables,这部分过于复杂,所以没有做实际解析。

5.生成时机

对于行模式的DML而言,生成时机是在事务的第一个DML语句的第一行数据修改之后。通常来讲,一个事务对应一个QUERY_EVENT。

DDL的生成时机在整个操作执行完成之后。