
1. 准备工作
参数配置:
binlog_format = ROW
binlog_rows_query_log_events = OFF
创建测试表:
CREATE TABLE `t_binlog` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`i1` int DEFAULT '0',
`str1` varchar(32) DEFAULT '',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
示例 SQL:
BEGIN;
INSERT INTO `t_binlog` (`i1`, `str1`)
VALUES (100, 'MySQL 核心模块揭秘');
COMMIT;
2. 解析
执行示例 SQL 之后,我们可以用下面的命令解析事务产生的 日志:
cd
mysqlbinlog binlog.000395
--base64-output=decode-rows -vv
解析 日志之后,我们可以得到 4 个 event。
按照这些 event 在 日志文件中的顺序,简化之后的内容如下:
# at 1233
# Query thread_id=8
BEGIN
# at 1308
Table_map: `test`.`t_binlog` mapped to number 95
# at 1369
Write_rows: table id 95 flags: STMT_END_F
INSERT INTO `test`.`t_binlog`
SET
@1=1 /* INT meta=0 nullable=0 is_null=0 */
@2=100 /* INT meta=0 nullable=1 is_null=0 */
@3='MySQL 核心模块揭秘' /* VARSTRING(96) meta=96 nullable=1 is_null=0 */
# at 1438
Xid = 32
COMMIT/*!*/;
示例 SQL 中,只有两条 SQL 会产生 event:
3. cache
我们使用 分析 日志的时候,可以发现这么一个现象:同一个事务产生的 event,在 日志文件中是连续的。
保证同一个事务的 event 在 日志文件中的连续性,不管是 MySQL 从库回放 ,还是作为用户的我们,都可以很方便的定位到一个事务的 从哪里开始,到哪里结束。
一个事务会产生多个 event,很多个事务同时执行,怎么保证同一个事务产生的 event 写入到 日志文件中是连续的?
这就是 cache 发挥用武之地的时候了,每个事务都有两个 cache:
因为我们只介绍 存储引擎,后面会忽略 ,直接介绍 。
事务执行过程中,产生的所有 event,都会先写入 。 分为两级:
加上临时文件中已经写入的 占用的字节数,也有一个上限,由系统变量 e 控制。
4. 产生
如果一条 SQL 语句改变了(插入、更新、删除)表中的数据, 层会为这条 SQL 语句产生一个包含表名和表 ID 的 。
每次调用存储引擎的方法写入一条记录到表中之后, 层都会为这条记录产生 。
这里没有写成 event,是因为记录中各字段内容都很少的时候,多条记录可以共享同一个 event ,并不需要为每条记录都产生一个新的 event。
多条记录产生的 共享同一个 event 时,这个 event 最多可以存放多少字节的内容,由系统变量 _size 控制,默认为 8192 字节。
如果一条记录产生的 超过了 8192 字节,它的 会独享一个 event,这个 event 的大小就不受系统变量 _size 控制了。
在 日志文件中, 位于 SQL 语句改变表中数据产生的 event 之前。
示例 SQL 对应的事务中, 是改变表中数据的第一条 SQL 语句,它插入第一条(也是唯一一条)记录到 表之后, 层会为这条记录产生 event。
插入记录对应的 event 是 。
产生 之前, 层会先为 构造一个 。
构造 之前, 层发现一个问题:示例 SQL 对应的事务,还没有初始化 cache。
那么,第一步就要为这个事务初始化 cache,包括 和 。初始化完成之后,这两个 cache 都是空的。
在 日志文件中,一个事务以内容为 BEGIN 的 开始。
刚刚初始化完成的 是空的,写入其它 event 之前,要先写入一个内容为 BEGIN 的 。
写入 之后,就可以写入内容为表名和表 ID 的 了。
写入 之后,接下来写入的 event 就是包含插入记录所有字段的 了。
最后,执行 语句时,会产生内容为 的 ,并写入 。
5. 怎么写入 ?
事务执行过程中,所有 event 都会先写入 的 , 大小默认为 32K。
如果 剩余空间不够写入一个 event, 和临时文件怎么协同合作,来完成这个 event 的写入操作?
接下来,我们就来聊聊,写入一个 event 到 的流程:
6. 总结
分为两级:内存()、临时文件。
事务执行过程中,产生的所有 event 都要写入 。
event 写入 ,通常情况下,都会先写入 ,写满 之后,再把 中所有内容都写入临时文件,最后清空 。
本期问题:如果 是空的,接下来要写入一个 86K 的 event 到 ,写入流程是什么样的?欢迎大家留言交流。
下期预告:MySQL 核心模块揭秘 | 07 期 | 二阶段提交 (1) 阶段。
更多技术文章,请访问:
关于 SQLE
SQLE 是一款全方位的 SQL 质量管理平台,覆盖开发至生产环境的 SQL 审核和管理。支持主流的开源、商业、国产数据库,为开发和运维提供流程自动化能力,提升上线效率,提高数据质量。




发表回复