您当前的位置:首页 > 电脑百科 > 数据库 > MYSQL

MySQL 核心模块揭秘,你看明白了吗?

时间:2024-03-27 15:16:14  来源:微信公众号  作者:爱可生开源社区
为了提升分配 undo 段的效率,事务提交过程中,InnoDB 会缓存一些 undo 段。只要同时满足两个条件,insert undo 段或 update undo 段就能被缓存。

1. 关于缓存 undo 段

为了提升分配 undo 段的效率,事务提交过程中,InnoDB 会缓存一些 undo 段。

只要同时满足两个条件,insert undo 段或 update undo 段就能被缓存。

条件 1:undo 段中只有一个 undo 页。

条件 2:这个唯一的 undo 页中,已经使用的的空间必须小于数据页大小的四分之三。以默认大小 16K 的 undo 页为例,undo 页中已经使用的空间必须小于 12K。

如果 insert undo 段满足缓存条件,它会加入回滚段的 insert_undo_cached 链表头部。

如果 update undo 段满足缓存条件,它会加入回滚段的 update_undo_cached 链表头部。

2. InnoDB 提交事务

二阶段提交过程中,commit 阶段的 flush 子阶段,把 prepare 阶段及之前产生的 redo 日志都刷盘了,把事务执行过程中产生的 binlog 日志都写入 binlog 日志文件了。

sync 子阶段根据系统变量 sync_binlog 的值决定是否触发操作系统把 binlog 日志刷盘。

前两个子阶段,都只处理了日志,不涉及 InnoDB 的事务。这两个阶段完成之后,InnoDB 的事务还没有提交,事务还处于准备提交状态(TRX_STATE_PREPARED)。

commit 子阶段才会真正提交 InnoDB 的事务,这个阶段完成之后,事务就提交完成了。

commit 子阶段提交 InnoDB 的事务,要做的事情有这些:

  • 修改 insert undo 段的状态。
  • 生成事务提交号,用于 purge 线程判断是否能清理某些 update undo 日志组中的 undo 日志。
  • 修改 update undo 段的状态。
  • 把 update undo 段中的 undo 日志组加入回滚段的 history list 链表。purge 线程会从这个链表中获取需要清理的 update undo 日志组。
  • 把事务状态修改为 TRX_STATE_COMMITTED_IN_MEMORY。
  • 释放事务执行过程中 InnoDB 给表或记录加的锁。
  • 重新初始化事务对象,以备当前线程后续使用。

2.1 修改 insert undo 段状态

如果事务插入记录到用户普通表,InnoDB 会为事务分配一个 insert undo 段。

如果事务插入记录到用户临时表,InnoDB 会为事务分配另一个 insert undo 段。

InnoDB 可能会给事务分配 0 ~ 2 个 insert undo 段。commit 子阶段会修分配给事务的所有 insert undo 段的状态。

如果 insert undo 段满足缓存条件,它的状态会被修改为 TRX_UNDO_CACHED,否则,它的状态会被修改为 TRX_UNDO_TO_FREE。

事务提交完成之后,InnoDB 会根据状态缓存或者释放 insert undo 段。

2.2 生成事务提交号

事务提交号是事务对象的 no 属性,通常用 trx->no 表示。

代码里,对事务提交号的注释是 transaction serialization number,直译成中文应该称为事务序列号,或者事务串行号。

因为 trx->no 是在事务提交时生成的,我们还是把它称为事务提交号更容易理解一些。

只有 update undo 段需要事务提交号。purge 线程清理 update undo 日志时,会根据 update undo 段的 undo 日志组中保存的事务提交号,决定是否能清理这个 undo 日志组中的 undo 日志。

修改 update undo 段的状态之前,InnoDB 会生成事务提交号,保存到事务对象的 no 属性中。

// storage/innobase/trx/trx0trx.cc
static inline bool trx_add_to_serialisation_list(trx_t *trx) {
  ...
  trx->no = trx_sys_allocate_trx_no();
  ...
}

trx_sys_allocate_trx_no() 调用 trx_sys_allocate_trx_id_or_no() 生成事务提交号。

// storage/innobase/include/trx0sys.ic
// 生成事务 ID
inline trx_id_t trx_sys_allocate_trx_id() {
  ut_ad(trx_sys_mutex_own());
  return trx_sys_allocate_trx_id_or_no();
}
// 生成事务提交号
inline trx_id_t trx_sys_allocate_trx_no() {
  ut_ad(trx_sys_serialisation_mutex_own());
  return trx_sys_allocate_trx_id_or_no();
}

从上面的代码可以看到,生成事务 ID 和事务提交号调用的是同一个方法,trx_sys_allocate_trx_id_or_no() 的代码如下:

// storage/innobase/include/trx0sys.ic
inline trx_id_t trx_sys_allocate_trx_id_or_no() {
  ...
  // trx_sys_allocate_trx_id_or_no() 每次被调用
  // trx_sys->next_trx_id_or_no 加 1
  // trx_id 保存的是加 1 之前的值
  trx_id_t trx_id = trx_sys->next_trx_id_or_no.fetch_add(1);
  ...
  return trx_id;
}

trx_sys->next_trx_id_or_no 保存的是下一个事务 ID 或事务提交号,具体是哪个,取决于是生成事务 ID 还是生成事务提交号先调用 trx_sys_allocate_trx_id_or_no()。

也就是说,事务 ID 和事务提交号是同一条流水线上生产出来的。我们以 trx 1 和 trx 2 两个事务为例,来说明生成事务 ID 和事务提交号的流程。

假设此时 trx_sys->next_trx_id_or_no 的值为 100,trx 1、trx 2 启动和提交的顺序如下:

  • trx 1 启动。
  • trx 2 启动。
  • trx 1 提交。
  • trx 2 提交。

其于以上假设,生成事务 ID 和事务提交号的流程如下:

  • trx 1 生成事务 ID,得到 100。trx_sys->next_trx_id_or_no 加 1,结果为 101。
  • trx 2 生成事务 ID,得到 101。trx_sys->next_trx_id_or_no 加 1,结果为 102。
  • trx 1 生成事务提交号,得到 102。trx_sys->next_trx_id_or_no 加 1,结果为 103。
  • trx 2 生成事务提交号,得到 103。trx_sys->next_trx_id_or_no 加 1,结果为 104。

从以上流程可以看到,事务 ID 和事务提交号都来源于 trx_sys->next_trx_id_or_no,相互之间不会重复。

2.3 修改 update undo 段状态

如果事务更新或删除了用户普通表的记录,InnoDB 会为事务分配一个 update undo 段。

如果事务更新或删除了用户临时表的记录,InnoDB 会为事务分配另一个 update undo 段。

InnoDB 可能会给事务分配 0 ~ 2 个 update undo 段。commit 子阶段会修改分配给事务的所有 update undo 段的状态。

如果 update undo 段满足缓存条件,它的状态会被修改为 TRX_UNDO_CACHED,否则,它的状态会被修改为 TRX_UNDO_TO_PURGE。

2.4 undo 日志组加入 history list

修改完 update undo 段的状态,update undo 段的 undo 日志组会加入回滚段的 history list 链表。purge 线程会从这个链表中获取要清理的 undo 日志组。

前面已经生成了事务提交号,这里会把事务提交号写入 undo 日志组的头信息中。

如果 update undo 段的状态为 TRX_UNDO_CACHED,表示这个 undo 段需要缓存起来。它会加入回滚段的 update_undo_cached 链表头部,以备后续其它事务需要 update undo 段时,能够快速分配。

3. InnoDB 提交事务完成

前面的一系列操作完成之后,InnoDB 提交事务的操作就完成了。

现在,要把事务状态修改为 TRX_STATE_COMMITTED_IN_MEMORY。

修改之后,新启动的事务就能看到该事务插入或更新的记录,看不到当前事务删除的记录。

接下来,InnoDB 会释放事务执行过程中加的表锁、记录锁。

释放锁之后,还要处理 insert undo 段。

如果 insert undo 段的状态为 TRX_UNDO_CACHED,表示这个 undo 段需要缓存起来。它会加入回滚段的 insert_undo_cached 链表头部,以备后续其它事物需要 insert undo 段时,能够快速分配。

如果 insert undo 段的状态为 TRX_UNDO_TO_FREE,它会被释放,占用的 undo 页会还给 undo 表空间。

二阶段提交的 flush 子阶段,已经把 prepare 阶段及之前产生的 redo 日志都刷盘了。

commit 子阶段,修改 insert undo 段和 update undo 段的状态,还会产生 redo 日志。

InnoDB 不会主动触发操作系统把这些 redo 日志刷盘,而是由操作系统决定什么时候把这些 redo 日志刷盘。

InnoDB 敢这么做,是因为这些 redo 日志对于确定事务状态已经不重要了。即使这些 redo 日志刷盘之前,服务器突然异常关机,导致 undo 段的状态丢失。MySQL 下次启动时,也能正确的识别到事务已经提交完成了。

4. 重新初始化事务对象

到这里,InnoDB 提交事务该做的操作都已经做完了。提交事务完成之后,该做的事也都做了。

对于上一个事务,事务对象的使命已经结束。这里会把事务状态修改为 TRX_STATE_NOT_STARTED。

事务对象也会被重新初始化,但是它不会被释放。也就是说,事务对象不会回到事务池中,而是留给当前连接后续启动新事务时复用。

5. 总结

InnoDB 提交事务,就像我们填完一个表格之后,最后盖上的那个戳,总体上来说,要干 3 件事。

第 1 件,修改分配给事务的各 undo 段的状态。

如果数据库发生崩溃,重新启动后,undo 段的状态是影响事务提交还是回滚的因素之一。

第 2 件,修改事务对象的状态。

如果数据据库一直运行,不发生崩溃,就靠事务对象的状态来标识事务是否已提交。

第 3 件,把各 undo 段中的 undo 日志组加入 history list 链表。

其它事务都不再需要使用这些 undo 日志时,后台 purge 线程会清理这些 undo 日志组中的日志。



Tags:MySQL   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
MySQL 核心模块揭秘
server 层会创建一个 SAVEPOINT 对象,用于存放 savepoint 信息。binlog 会把 binlog offset 写入 server 层为它分配的一块 8 字节的内存里。 InnoDB 会维护自己的 savepoint...【详细内容】
2024-04-03  Search: MySQL  点击:(5)  评论:(0)  加入收藏
MySQL 核心模块揭秘,你看明白了吗?
为了提升分配 undo 段的效率,事务提交过程中,InnoDB 会缓存一些 undo 段。只要同时满足两个条件,insert undo 段或 update undo 段就能被缓存。1. 关于缓存 undo 段为了提升分...【详细内容】
2024-03-27  Search: MySQL  点击:(10)  评论:(0)  加入收藏
MySQL:BUG导致DDL语句无谓的索引重建
对于5.7.23之前的版本在评估类似DDL操作的时候需要谨慎,可能评估为瞬间操作,但是实际上线的时候跑了很久,这个就容易导致超过维护窗口,甚至更大的故障。一、问题模拟使用5.7.22...【详细内容】
2024-03-26  Search: MySQL  点击:(8)  评论:(0)  加入收藏
从 MySQL 到 ByteHouse,抖音精准推荐存储架构重构解读
ByteHouse是一款OLAP引擎,具备查询效率高的特点,在硬件需求上相对较低,且具有良好的水平扩展性,如果数据量进一步增长,可以通过增加服务器数量来提升处理能力。本文将从兴趣圈层...【详细内容】
2024-03-22  Search: MySQL  点击:(23)  评论:(0)  加入收藏
MySQL自增主键一定是连续的吗?
测试环境:MySQL版本:8.0数据库表:T (主键id,唯一索引c,普通字段d)如果你的业务设计依赖于自增主键的连续性,这个设计假设自增主键是连续的。但实际上,这样的假设是错的,因为自增主键不...【详细内容】
2024-03-10  Search: MySQL  点击:(5)  评论:(0)  加入收藏
准线上事故之MySQL优化器索引选错
1 背景最近组里来了许多新的小伙伴,大家在一起聊聊技术,有小兄弟提到了MySQL的优化器的内部策略,想起了之前在公司出现的一个线上问题,今天借着这个机会,在这里分享下过程和结论...【详细内容】
2024-03-07  Search: MySQL  点击:(26)  评论:(0)  加入收藏
MySQL数据恢复,你会吗?
今天分享一下binlog2sql,它是一款比较常用的数据恢复工具,可以通过它从MySQL binlog解析出你要的SQL,并根据不同选项,可以得到原始SQL、回滚SQL、去除主键的INSERT SQL等。主要...【详细内容】
2024-02-22  Search: MySQL  点击:(41)  评论:(0)  加入收藏
如何在MySQL中实现数据的版本管理和回滚操作?
实现数据的版本管理和回滚操作在MySQL中可以通过以下几种方式实现,包括使用事务、备份恢复、日志和版本控制工具等。下面将详细介绍这些方法。1.使用事务:MySQL支持事务操作,可...【详细内容】
2024-02-20  Search: MySQL  点击:(50)  评论:(0)  加入收藏
为什么高性能场景选用Postgres SQL 而不是 MySQL
一、 数据库简介 TLDR;1.1 MySQL MySQL声称自己是最流行的开源数据库,它属于最流行的RDBMS (Relational Database Management System,关系数据库管理系统)应用软件之一。LAMP...【详细内容】
2024-02-19  Search: MySQL  点击:(36)  评论:(0)  加入收藏
MySQL数据库如何生成分组排序的序号
经常进行数据分析的小伙伴经常会需要生成序号或进行数据分组排序并生成序号。在MySQL8.0中可以使用窗口函数来实现,可以参考历史文章有了这些函数,统计分析事半功倍进行了解。...【详细内容】
2024-01-30  Search: MySQL  点击:(53)  评论:(0)  加入收藏
▌简易百科推荐
MySQL 核心模块揭秘
server 层会创建一个 SAVEPOINT 对象,用于存放 savepoint 信息。binlog 会把 binlog offset 写入 server 层为它分配的一块 8 字节的内存里。 InnoDB 会维护自己的 savepoint...【详细内容】
2024-04-03  爱可生开源社区    Tags:MySQL   点击:(5)  评论:(0)  加入收藏
MySQL 核心模块揭秘,你看明白了吗?
为了提升分配 undo 段的效率,事务提交过程中,InnoDB 会缓存一些 undo 段。只要同时满足两个条件,insert undo 段或 update undo 段就能被缓存。1. 关于缓存 undo 段为了提升分...【详细内容】
2024-03-27  爱可生开源社区  微信公众号  Tags:MySQL   点击:(10)  评论:(0)  加入收藏
MySQL:BUG导致DDL语句无谓的索引重建
对于5.7.23之前的版本在评估类似DDL操作的时候需要谨慎,可能评估为瞬间操作,但是实际上线的时候跑了很久,这个就容易导致超过维护窗口,甚至更大的故障。一、问题模拟使用5.7.22...【详细内容】
2024-03-26  MySQL学习  微信公众号  Tags:MySQL   点击:(8)  评论:(0)  加入收藏
从 MySQL 到 ByteHouse,抖音精准推荐存储架构重构解读
ByteHouse是一款OLAP引擎,具备查询效率高的特点,在硬件需求上相对较低,且具有良好的水平扩展性,如果数据量进一步增长,可以通过增加服务器数量来提升处理能力。本文将从兴趣圈层...【详细内容】
2024-03-22  字节跳动技术团队    Tags:ByteHouse   点击:(23)  评论:(0)  加入收藏
MySQL自增主键一定是连续的吗?
测试环境:MySQL版本:8.0数据库表:T (主键id,唯一索引c,普通字段d)如果你的业务设计依赖于自增主键的连续性,这个设计假设自增主键是连续的。但实际上,这样的假设是错的,因为自增主键不...【详细内容】
2024-03-10    dbaplus社群  Tags:MySQL   点击:(5)  评论:(0)  加入收藏
准线上事故之MySQL优化器索引选错
1 背景最近组里来了许多新的小伙伴,大家在一起聊聊技术,有小兄弟提到了MySQL的优化器的内部策略,想起了之前在公司出现的一个线上问题,今天借着这个机会,在这里分享下过程和结论...【详细内容】
2024-03-07  转转技术  微信公众号  Tags:MySQL   点击:(26)  评论:(0)  加入收藏
MySQL数据恢复,你会吗?
今天分享一下binlog2sql,它是一款比较常用的数据恢复工具,可以通过它从MySQL binlog解析出你要的SQL,并根据不同选项,可以得到原始SQL、回滚SQL、去除主键的INSERT SQL等。主要...【详细内容】
2024-02-22  数据库干货铺  微信公众号  Tags:MySQL   点击:(41)  评论:(0)  加入收藏
如何在MySQL中实现数据的版本管理和回滚操作?
实现数据的版本管理和回滚操作在MySQL中可以通过以下几种方式实现,包括使用事务、备份恢复、日志和版本控制工具等。下面将详细介绍这些方法。1.使用事务:MySQL支持事务操作,可...【详细内容】
2024-02-20  编程技术汇    Tags:MySQL   点击:(50)  评论:(0)  加入收藏
MySQL数据库如何生成分组排序的序号
经常进行数据分析的小伙伴经常会需要生成序号或进行数据分组排序并生成序号。在MySQL8.0中可以使用窗口函数来实现,可以参考历史文章有了这些函数,统计分析事半功倍进行了解。...【详细内容】
2024-01-30  数据库干货铺  微信公众号  Tags:MySQL   点击:(53)  评论:(0)  加入收藏
mysql索引失效的场景
MySQL中索引失效是指数据库查询时无法有效利用索引,这可能导致查询性能显著下降。以下是一些常见的MySQL索引失效的场景:1.使用非前导列进行查询: 假设有一个复合索引 (A, B)。...【详细内容】
2024-01-15  小王爱编程  今日头条  Tags:mysql索引   点击:(82)  评论:(0)  加入收藏
站内最新
站内热门
站内头条