首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >mysql binlog中QUERY_EVENT的status_var结构

mysql binlog中QUERY_EVENT的status_var结构

原创
作者头像
大大刺猬
发布2026-03-27 17:46:18
发布2026-03-27 17:46:18
1280
举报
文章被收录于专栏:大大刺猬大大刺猬

导读

我们两年前有讲过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++
复制
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
复制
# 完整的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
复制
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++
复制
  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
复制
    &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
复制
# 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
复制
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
复制
# 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的结构虽然比较简单, 但涉及的内容还蛮多的, 我们画个图来总结下(这熟悉的超长图又回来了):

参考: https://dev.mysql.com/doc/dev/mysql-server/8.4.7/page_protocol_replication_binlog_event.html

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导读
    • QUERY_EVENT = 2
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档