mysql binlog中QUERY_EVENT的status_var结构

导读

我们两年前有讲过QUERY_EVENT的结构, 但对于其中的status_var讲得比较浅. 所以本次来完善完善,为后面的使用打下基础.

QUERY_EVENT = 2

明文的SQL,ROW模式下通常是DDL,STATEMENT就主要是DML了. 官方文档里面的名字和mysqlbinlog解析出来的名字有区别的, 我就按照mysqlbinlog解析的名字来(更好理解)

文档里面的slave_proxy_id和本文的thread_id是一样的, 但感觉没得thread_id好理解...

对象 大小 描述
thread_id 4 产生该SQL的thread_id, 就是show processlist看到的那个id
exec_time 4 该SQL执行的时间. 单位是秒, 所以精度也就到秒了.
schema_len 1 数据库名长度,执行该SQL时默认的schema名字.(如果没有use db的话, 就是0)
error_code 2 该SQL对应的错误码
status_vars_len 2 如果binlog-version>4的话, 才有这玩意. 记录有多少个状态码.每个状态码1字节
status_vars status_vars_len 具体的状态码
schema schema_len+1 数据库名, 即使有数据库名也不一定要输出, 还得看event_header的flags是否没有LOG_EVENT_SUPPRESS_USE_F. 不管有没有数据库名,都是\x00结尾
query 剩下的都是(除了checksum) DDL

那么状态码status_vars有哪些呢?

status_vars

status_vars是key/value对应的, key固定1字节, value根据key来

key的各value大小如下:

keyid key对象名 对应的value大小 描述
0x00 Q_FLAGS2_CODE 4 一些flag
0x01 Q_SQL_MODE_CODE 8 sql_mode相关的
0x02 Q_CATALOG_CODE 1+n+1 5.0.0-3才有的,应该是元数据信息.
0x03 Q_AUTO_INCREMENT 2+2 如果自增(auto_increment)大于1,就有这玩意,起始就是auto_increment_increment+auto_increment_offset
0x04 Q_CHARSET_CODE 2+2+2 字符集相关的
0x05 Q_TIME_ZONE_CODE 1+n 时区相关的
0x06 Q_CATALOG_NZ_CODE 1+n catalog相关的
0x07 Q_LC_TIME_NAMES_CODE 2 和LC_TIME 相关的
0x08 Q_CHARSET_DATABASE_CODE 2 库级别的字符集
0x09 Q_TABLE_MAP_FOR_UPDATE_CODE 8 row格式下多表的更新的table_map
0x0a Q_SOURCE_DATA_WRITTEN_CODE 4 以前叫Q_MASTER_DATA_WRITTEN_CODE
0x0b Q_INVOKERS 1+n+1+n invoker相关的, 就是User+host
0x0c Q_UPDATED_DB_NAMES 1+n*nul-term-string 受影响的数据库信息, 1字节数量, 跟上这么多个以\x00结尾的库
0x0d Q_MICROSECONDS 3 时间精度
0x0e Q_COMMIT_TS 8 同G_COMMIT_TS
0x0f Q_COMMIT_TS2 8 替代Q_COMMIT_TS的,同G_COMMIT_TS2
0x10 Q_EXPLICIT_DEFAULTS_FOR_TIMESTAMP 1 就是explicit_defaults_for_timestamp
0x11 Q_DDL_LOGGED_WITH_XID 8 xid
0x12 Q_DEFAULT_COLLATION_FOR_UTF8MB4 2 utf8mb4默认的collation
0x13 Q_SQL_REQUIRE_PRIMARY_KEY 2 参数sql_require_primary_key
0x14 Q_DEFAULT_TABLE_ENCRYPTION 2 参数default_table_encryption

来看看各key对应的value的取值:

Q_FLAGS2_CODE

Q_FLAGS2_CODE 记录一些query_options. 4字节能记录32个, 但实际上有37种(8.0有40种), 不过后面的都用不到, 实际上前面的也就几种会出现在Binlog里面(binlog记录写,不记录读). 其实就是一些变量值

id 对象 描述
0 SELECT_DISTINCT
1 SELECT_STRAIGHT_JOIN
2 SELECT_DESCRIBE
3 SELECT_SMALL_RESULT
4 SELECT_BIG_RESULT
5 OPTION_FOUND_ROWS
6 OPTION_TO_QUERY_CACHE
7 SELECT_NO_JOIN_CACHE
8 OPTION_AUTOCOMMIT
9 OPTION_BIG_SELECTS
10 OPTION_LOG_OFF
11 OPTION_QUOTE_SHOW_CREATE
12 TMP_TABLE_ALL_COLUMNS
13 OPTION_WARNINGS
14 OPTION_AUTO_IS_NULL 对应sql_auto_is_null
15 OPTION_FOUND_COMMENT
16 OPTION_SAFE_UPDATES
17 OPTION_BUFFER_RESULT
18 OPTION_BIN_LOG
19 OPTION_NOT_AUTOCOMMIT 对应autocommit
20 OPTION_BEGIN
21 OPTION_TABLE_LOCK
22 OPTION_QUICK
23 OPTION_NO_CONST_TABLES
24 SELECT_ALL
25 SELECT_NO_SEMI_JOIN
26 OPTION_NO_FOREIGN_KEY_CHECKS 对应foreign_key_checks
27 OPTION_RELAXED_UNIQUE_CHECKS 对应unique_checks
28 SELECT_NO_UNLOCK
29 OPTION_SCHEMA_TABLE
30 OPTION_SETUP_TABLES_DONE
31 OPTION_SQL_NOTES
32 TMP_TABLE_FORCE_MYISAM
33 OPTION_PROFILING
34 SELECT_HIGH_PRIORITY
35 OPTION_MASTER_SQL_ERROR
36 OPTION_ALLOW_BATCH
37 OPTION_SELECT_FOR_SHOW
38 OPTION_DD_UPDATE_CONTEXT
39 OPTION_NO_SUBQUERY_DURING_OPTIMIZATION

实际上写binlog的就4个, 即

代码语言:c++

AI代码解释

复制代码
OPTIONS_WRITTEN_TO_BIN_LOG = (OPTION_AUTO_IS_NULL|OPTION_NO_FOREIGN_KEY_CHECKS|OPTION_RELAXED_UNIQUE_CHECKS|OPTION_NOT_AUTOCOMMIT)
Q_SQL_MODE_CODE

再来看看Q_SQL_MODE_CODE,其实看名字都知道是sql_mode了.

这玩意使用8字节, 也就是能表示64种sql_mode值. 我们之前也有讲过sql_mode有哪些:https://cloud.tencent.com/developer/article/2600365

但实际上就32种: 如下

bitmask name 描述
1<<0 MODE_REAL_AS_FLOAT
1<<1 MODE_PIPES_AS_CONCAT
1<<2 MODE_ANSI_QUOTES
1<<3 MODE_IGNORE_SPACE
1<<4 MODE_NOT_USED
1<<5 MODE_ONLY_FULL_GROUP_BY
1<<6 MODE_NO_UNSIGNED_SUBTRACTION
1<<7 MODE_NO_DIR_IN_CREATE
1<<8 MODE_POSTGRESQL
1<<9 MODE_ORACLE
1<<10 MODE_MSSQL
1<<11 MODE_DB2
1<<12 MODE_MAXDB
1<<13 MODE_NO_KEY_OPTIONS
1<<14 MODE_NO_TABLE_OPTIONS
1<<15 MODE_NO_FIELD_OPTIONS
1<<16 MODE_MYSQL323
1<<17 MODE_MYSQL40
1<<18 MODE_ANSI
1<<19 MODE_NO_AUTO_VALUE_ON_ZERO
1<<20 MODE_NO_BACKSLASH_ESCAPES
1<<21 MODE_STRICT_TRANS_TABLES
1<<22 MODE_STRICT_ALL_TABLES
1<<23 MODE_NO_ZERO_IN_DATE
1<<24 MODE_NO_ZERO_DATE
1<<25 MODE_INVALID_DATES
1<<26 MODE_ERROR_FOR_DIVISION_BY_ZERO
1<<27 MODE_TRADITIONAL
1<<28 MODE_NO_AUTO_CREATE_USER
1<<29 MODE_HIGH_NOT_PRECEDENCE
1<<30 MODE_NO_ENGINE_SUBSTITUTION
1<<31 MODE_PAD_CHAR_TO_FULL_LENGTH
Q_CATALOG_CODE

5.0.0-5.0.3版本才有的, 结构如下:

对象 大小 描述
len 1 大小
data len
end 1 \x00
Q_AUTO_INCREMENT

就是记录自增的起始值和步长. 使用2+2字节. 所以自增起始值auto_increment_offset最大是65535, 步长auto_increment_increment也是最大65536.

所以我们解析binlog的时候,也要像mysqlbinlog那样列出关键信息(SET @@session.auto_increment_increment=65535, @@session.auto_increment_offset=1234/*!*/;)

对象 大小 描述
auto_increment_increment 2 自增步长
auto_increment_offset 2 自增初始值

比如:

代码语言:txt

AI代码解释

复制代码
# 完整的event paload
b'\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\x00\x00\x00\x00\x00\x00\x01 \x00\xa0U\x00\x00\x00\x00\x06\x03std\x03\xff\xff\xd2\x04\x04!\x00!\x00!\x00\x0c\x01db1\x00\x00create table db1.t20260327_02(id int auto_increment,c1 int,key(id))\xe3\x82[\xdf'

# status_vars
b'\x00\x00\x00\x00\x00\x01 \x00\xa0U\x00\x00\x00\x00\x06\x03std\x03\xff\xff\xd2\x04\x04!\x00!\x00!\x00\x0c\x01db1\x00'

# Q_AUTO_INCREMENT
b'\x03\xff\xff\xd2\x04'
03
65536
1234
Q_CHARSET_CODE

字符集相关的.

对象 大小 描述
character_set_client 2 客户端字符集
collation_connection 2 连接的collation
collation_server 2 server得到collation
Q_TIME_ZONE_CODE

时区相关的.

对象 大小 描述
len 1 长度
time_zone len 时区
Q_CATALOG_NZ_CODE

5.0.4及其之后才有的,

对象 大小 描述
len 1 长度
catalog len catalog

比如:

代码语言:txt

AI代码解释

复制代码
b'\x06\x03std'
len:03
catalog:std
Q_LC_TIME_NAMES_CODE 0x07

和LC_TIME相关的,定义怎么解析week-,day-name之类的. 固定2字节.

对象 大小 描述
lc_code 2 lc_time_names

虽然使用2字节, 但实际上就111种. 代码里面判断的时候就考虑255, 但非要2字节,不知道为啥...

代码语言:c++

AI代码解释

复制代码
  if (lc_time_names_number) {
    assert(lc_time_names_number <= 0xFF);
    *start++ = Q_LC_TIME_NAMES_CODE;
    int2store(start, lc_time_names_number);
    start += 2;
  }

如下: 0就是my_locale_en_US, 1就是my_locale_en_GB 依此类推

代码语言:txt

AI代码解释

复制代码
    &my_locale_en_US, &my_locale_en_GB, &my_locale_ja_JP, &my_locale_sv_SE,
    &my_locale_de_DE, &my_locale_fr_FR, &my_locale_ar_AE, &my_locale_ar_BH,
    &my_locale_ar_JO, &my_locale_ar_SA, &my_locale_ar_SY, &my_locale_be_BY,
    &my_locale_bg_BG, &my_locale_ca_ES, &my_locale_cs_CZ, &my_locale_da_DK,
    &my_locale_de_AT, &my_locale_es_ES, &my_locale_et_EE, &my_locale_eu_ES,
    &my_locale_fi_FI, &my_locale_fo_FO, &my_locale_gl_ES, &my_locale_gu_IN,
    &my_locale_he_IL, &my_locale_hi_IN, &my_locale_hr_HR, &my_locale_hu_HU,
    &my_locale_id_ID, &my_locale_is_IS, &my_locale_it_CH, &my_locale_ko_KR,
    &my_locale_lt_LT, &my_locale_lv_LV, &my_locale_mk_MK, &my_locale_mn_MN,
    &my_locale_ms_MY, &my_locale_nb_NO, &my_locale_nl_NL, &my_locale_pl_PL,
    &my_locale_pt_BR, &my_locale_pt_PT, &my_locale_ro_RO, &my_locale_ru_RU,
    &my_locale_ru_UA, &my_locale_sk_SK, &my_locale_sl_SI, &my_locale_sq_AL,
    &my_locale_sr_RS, &my_locale_ta_IN, &my_locale_te_IN, &my_locale_th_TH,
    &my_locale_tr_TR, &my_locale_uk_UA, &my_locale_ur_PK, &my_locale_vi_VN,
    &my_locale_zh_CN, &my_locale_zh_TW, &my_locale_ar_DZ, &my_locale_ar_EG,
    &my_locale_ar_IN, &my_locale_ar_IQ, &my_locale_ar_KW, &my_locale_ar_LB,
    &my_locale_ar_LY, &my_locale_ar_MA, &my_locale_ar_OM, &my_locale_ar_QA,
    &my_locale_ar_SD, &my_locale_ar_TN, &my_locale_ar_YE, &my_locale_de_BE,
    &my_locale_de_CH, &my_locale_de_LU, &my_locale_en_AU, &my_locale_en_CA,
    &my_locale_en_IN, &my_locale_en_NZ, &my_locale_en_PH, &my_locale_en_ZA,
    &my_locale_en_ZW, &my_locale_es_AR, &my_locale_es_BO, &my_locale_es_CL,
    &my_locale_es_CO, &my_locale_es_CR, &my_locale_es_DO, &my_locale_es_EC,
    &my_locale_es_GT, &my_locale_es_HN, &my_locale_es_MX, &my_locale_es_NI,
    &my_locale_es_PA, &my_locale_es_PE, &my_locale_es_PR, &my_locale_es_PY,
    &my_locale_es_SV, &my_locale_es_US, &my_locale_es_UY, &my_locale_es_VE,
    &my_locale_fr_BE, &my_locale_fr_CA, &my_locale_fr_CH, &my_locale_fr_LU,
    &my_locale_it_IT, &my_locale_nl_BE, &my_locale_no_NO, &my_locale_sv_FI,
    &my_locale_zh_HK, &my_locale_el_GR, &my_locale_rm_CH, nullptr};
Q_CHARSET_DATABASE_CODE 0x08

库级别的字符集, 2字节表示

对象 大小 描述
charset 2 字符集
Q_TABLE_MAP_FOR_UPDATE_CODE 0x09

多表更新时候使用的, 比如update db1.t20260327 as a, db1.t20260327_02 as b set a.id=666601,b.id=666602;

使用8字节表示, 每个bit对应1张表

对象 大小 描述
table_map_bitmask 8

比如:

代码语言:txt

AI代码解释

复制代码
# sql: update db1.t20260327 as a, db1.t20260327_02 as b set a.id=666601,b.id=666602;
# payload
b'\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00\x00\x00\x00\x01 \x00\xa0U\x00\x00\x00\x00\x06\x03std\x03\xff\xff\xd2\x04\x04!\x00!\x00!\x00\x07n\x00\t\x03\x00\x00\x00\x00\x00\x00\x00\x00BEGINm\x9c\x1bh'
# Q_TABLE_MAP_FOR_UPDATE_CODE 
b'\t\x03\x00\x00\x00\x00\x00\x00\x00'
  b'\x03\x00\x00\x00\x00\x00\x00\x00'
  也就是3, 即'00000011'  1bit对应1张表.所以是更新的前面2张表
  
# sql: update db1.t20260327 as a, db1.t20260327_02 as b set b.id=777702;
# payload
b'\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00\x00\x00\x00\x01 \x00\xa0U\x00\x00\x00\x00\x06\x03std\x03\xff\xff\xd2\x04\x04!\x00!\x00!\x00\x07n\x00\t\x02\x00\x00\x00\x00\x00\x00\x00\x00BEGIN3\x9d\xab\xcc'
# Q_TABLE_MAP_FOR_UPDATE_CODE
b'\t\x02\x00\x00\x00\x00\x00\x00\x00'
  b'\x02\x00\x00\x00\x00\x00\x00\x00'
  也就是2,即'00000010' 1bit对应1张表, 所以是更新的第二张表.

感觉多此一举

Q_SOURCE_DATA_WRITTEN_CODE

这条SQL产生了多少日志? 也没啥用

对象 大小 描述
size 4
Q_INVOKERS

记录INVOKERS的. 如下:

对象 大小 描述
username_length 1 用户名大小
username username_length 用户名
hostname_length 1 主机名大小
hostname hostname_length 主机名
Q_UPDATED_DB_NAMES

受影响的库信息

对象 大小 描述
count 1 数据库数量
dbname count(dbname+1) 具体的库信息

比如:

代码语言:txt

AI代码解释

复制代码
b'\x0c\x01db1\x00'
12			0x0c
count=1 	0x01
	db1	db1\x00
Q_MICROSECONDS

如果是statement之类的, 则使用3字节来记录精度, 比如执行SQLinsert into db1.t20260327_03 values(4,now(6));

对象 大小 描述
frac 3 时间的精度.

比如:

代码语言:txt

AI代码解释

复制代码
# status_vars
b'\x00\x00\x00\x00\x00\x01 \x00\xa0U\x00\x00\x00\x00\x06\x03std\x03\xff\xff\xd2\x04\x04!\x00!\x00!\x00\x05\x06SYSTEM\x07n\x00\x0c\x01db1\x00\r\xfe\x14\x05'

# Q_MICROSECONDS
b'\r\xfe\x14\x05'
b'\r' 				13
b'\xfe\x14\x05'  	33305 # 精度是小端字节序的, 可以在末尾加\x00, 方便使用struct.unpack('<L',)来做

总结

QUERY_EVENT的结构虽然比较简单, 但涉及的内容还蛮多的, 我们画个图来总结下(这熟悉的超长图又回来了):

相关推荐
Skilce7 小时前
ZrLog 高可用部署
运维·服务器·数据库·阿里云·maven
indexsunny10 小时前
互联网大厂Java求职面试实战:微服务与Spring生态全攻略
java·数据库·spring boot·安全·微服务·面试·消息队列
沪漂阿龙10 小时前
别再让数据库“吃”脏数据了!一文讲透MySQL约束,从入门到精通
数据库·mysql
skiy11 小时前
java与mysql连接 使用mysql-connector-java连接msql
java·开发语言·mysql
2401_8735449212 小时前
使用Python进行PDF文件的处理与操作
jvm·数据库·python
虾..12 小时前
多路复用 --- select系统调用
服务器·数据库·sql
杨云龙UP12 小时前
mysqldump逻辑备份文件恢复总结:全库恢复、单库恢复,一篇讲明白
linux·运维·服务器·数据库·mysql·adb
ybwycx12 小时前
mysql重置root密码(适用于5.7和8.0)
数据库·mysql·adb
色空大师13 小时前
【网站搭建实操(一)环境部署】
java·linux·数据库·mysql·网站搭建