1.MySQL 核心模块揭秘 | 13 期 | 回滚到 savepoint
2.MySQL全文索引源码剖析之Insert语句执行过程
3.MySQL 核心模块揭秘 | 12 期 | 创建 savepoint
4.MySQL:排序(filesort)详细解析(8000字长文)
5.故障分析 | 从 Insert 并发死锁分析 Insert 加锁源码逻辑
6.慢查询日志中的源码 Lock_time 从哪里来?
MySQL 核心模块揭秘 | 13 期 | 回滚到 savepoint
深入理解 MySQL,了解如何实现部分回滚操作。解读本文由技术专家操盛春撰写,源码他在公众号『一树一溪』分享 MySQL 和 OceanBase 源码研究。解读本文基于 MySQL 8.0.,源码InnoDB 存储引擎,解读汽车服务前端源码探讨核心模块的源码工作原理。
首先,解读我们创建测试表并插入数据。源码关键操作分为四个阶段,解读编号为 SQL 1 至 SQL 4,源码其中 SQL 4 是解读讨论焦点。SQL 2 和 SQL 3 分别产生 undo 日志 0 和 1。源码
当执行事务时,解读产生的源码 binlog 日志在 trx cache 中。回滚整个事务时,需要清除这些日志。然而,实际操作中,binlog 回滚步骤看似简单,却并未执行真正清除,只是为后续的 InnoDB 回滚做准备。
InnoDB 回滚是关键环节,它会根据 undo 日志执行反向操作,恢复事务影响的数据。以 SQL 为例,会从最新的 undo 日志开始回滚,逐条执行反向操作,包括记录的删除。
回滚后,事务的执行状态需要通过提交事务来更新。这不同于 commit 语句,因为回滚操作已经改变了数据,即使从逻辑上看恢复了原样,也需要将 InnoDB 中的修改正式提交。
trx cache 中的 binlog 日志会在 InnoDB 回滚完成后进行清除,这个过程涉及内存 buffer 和磁盘临时文件。binlog 回滚步骤延迟到这个阶段,是冒险岛源码泄露因为在事务提交前,binlog 日志并不需要写入持久化存储。
总结起来,MySQL 的部分回滚包括:无实际动作的 binlog 回滚,执行 InnoDB 回滚恢复数据,然后提交 InnoDB 事务,最后清理 trx cache 中的临时 binlog。如果你对文中内容有疑问,欢迎留言交流。
对于 SQL 质量管理,如需更多工具支持,可以了解 SQLE,一个覆盖开发到生产环境的 SQL 管理平台,提供流程自动化和数据质量管理功能。
MySQL全文索引源码剖析之Insert语句执行过程
本文来源于华为云社区,作者为GaussDB数据库,探讨了MySQL全文索引源码中Insert语句的执行过程。
全文索引是一种常用于信息检索的技术,它通过倒排索引实现,即单词和文档的映射关系,如(单词,(文档,偏移))。以创建一个表并在opening_line列上建立全文索引为例,插入'Call me Ishmael.'时,文档会被分为'call', 'me', 'ishmael'等单词,并记录在全文索引中。
全文索引Cache的作用类似于Change Buffer,用于缓存分词结果,避免频繁刷盘。Innodb使用fts_cache_t结构来管理cache,每个全文索引的表都会在内存中创建一个fts_cache_t对象。
Insert语句的执行分为三个阶段:写入行记录阶段、事务提交阶段和刷脏阶段。写入行记录阶段生成doc_id并写入Innodb的行记录,并将doc_id缓存。事务提交阶段对文档进行分词,获取{ 单词,(文档,ios如何拿到app源码偏移)}关联对,并插入到cache。刷脏阶段后台线程将cache刷新到磁盘。
全文索引的并发插入可能导致OOM问题,可通过修复patch #解决。当MySQL进程崩溃时,fts_init_index函数会恢复crash前的cache数据。
MySQL 核心模块揭秘 | 期 | 创建 savepoint
回滚操作,除了回滚整个事务,还可以部分回滚。部分回滚,需要保存点(savepoint)的协助。本文我们先看看保存点里面都有什么。
作者:操盛春,爱可生技术专家,公众号『一树一溪』作者,专注于研究 MySQL 和 OceanBase 源码。 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源
本文基于 MySQL 8.0. 源码,存储引擎为 InnoDB。
InnoDB 的事务对象有一个名为undo_no 的属性。事务每次改变(插入、更新、删除)某个表的一条记录,都会产生一条 undo 日志。这条 undo 日志中会存储它自己的序号。这个序号就来源于事务对象的 undo_no 属性。
也就是说,事务对象的 undo_no 属性中保存着事务改变(插入、更新、删除)某个表中下一条记录产生的 undo 日志的序号。
每个事务都维护着各自独立的 undo 日志序号,和其它事务无关。
每个事务的 undo 日志序号都从 0 开始。事务产生的第 1 条 undo 日志的序号为 0,第 2 条 undo 日志的序号为 1,依此类推。加盟自动发卡网源码
InnoDB 的 savepoint 结构中会保存创建 savepoint 时事务对象的 undo_no 属性值。
我们通过 SQL 语句创建一个 savepoint 时,server 层、binlog、InnoDB 会各自创建用于保存 savepoint 信息的结构。
server 层的 savepoint 结构是一个SAVEPOINT 类型的对象,主要属性如下:
binlog 的 savepoint 结构很简单,是一个 8 字节的整数。这个整数的值,是创建 savepoint 时事务已经产生的 binlog 日志的字节数,也是接下来新产生的 binlog 日志写入 trx_cache 的 offset。
为了方便介绍,我们把这个整数值称为binlog offset。
InnoDB 的 savepoint 结构是一个trx_named_savept_t 类型的对象,主要属性如下:
创建 savepoint 时,server 层会分配一块 字节的内存,除了存放它自己的 SAVEPOINT 对象,还会存放 binlog offset 和 InnoDB 的 trx_named_savept_t 对象。
server 层的 SAVEPOINT 对象占用这块内存的前 字节,InnoDB 的 trx_named_savept_t 对象占用中间的 字节,binlog offset 占用最后的 8 字节。
客户端连接到 MySQL 之后,MySQL 会分配一个专门用于该连接的用户线程。
用户线程中有一个m_savepoints 链表,用户创建的多个 savepoint 通过 prev 属性形成链表,m_savepoints 就指向最新创建的 savepoint。
server 层创建 savepoint 之前,会按照创建时间从新到老,逐个查看链表中是否存在和本次创建的 savepoint 同名的 savepoint。
如果在用户线程的 m_savepoints 链表中找到了和本次创建的 savepoint 同名的 savepoint,需要先删除 m_savepoints 链表中的同名 savepoint。
找到的同名 savepoint,是 server 层的SAVEPOINT 对象,它后面的内存区域分别保存着 InnoDB 的 trx_named_savept_t 对象、binlog offset。
binlog 是个老实孩子,乖乖的把 binlog offset 写入了 server 层为它分配的内存里。删除同名 savepoint 时,源码如何导入网页不需要单独处理 binlog offset。
InnoDB 就不老实了,虽然 server 层也为 InnoDB 的 trx_named_savept_t 对象分配了内存,但是 InnoDB 并没有往里面写入内容。
事务执行过程中,用户每次创建一个 savepoint,InnoDB 都会创建一个对应的 trx_named_savept_t 对象,并加入 InnoDB 事务对象的 trx_savepoints 链表的末尾。
因为 InnoDB 自己维护了一个存放 savepoint 结构的链表,server 层删除同名 savepoint 时,InnoDB 需要找到这个链表中对应的 savepoint 结构并删除,流程如下:
InnoDB 从事务对象的 trx_savepoints 链表中删除 trx_named_savept_t 对象之后,server 层接着从用户线程的 m_savepoints 链表中删除 server 层的SAVEPOINT 对象,也就连带着清理了 binlog offset。
处理完查找、删除同名 savepoint 之后,server 层就正式开始创建 savepoint 了,这个过程分为 3 步。
第 1 步,binlog 会生成一个 Query_log_event。
以创建名为test_savept 的 savepoint 为例,这个 event 的内容如下:
binlog event 写入 trx_cache 之后,binlog offset 会写入 server 层为它分配的 8 字节的内存中。
第 2 步,InnoDB 创建 trx_named_savept_t 对象,并放入事务对象的 trx_savepoints 链表的末尾。
trx_named_savept_t 对象的 name 属性值是 InnoDB 的 savepoint 名字。这个名字是根据 server 层为 InnoDB 的 trx_named_savept_t 对象分配的内存的地址计算得到的。
trx_named_savept_t 对象的savept 属性,是一个 trx_savept_t 类型的对象。这个对象里保存着创建 savepoint 时,事务对象中 undo_no 属性的值,也就是下一条 undo 日志的序号。
第 3 步,把 server 层的 SAVEPOINT 对象加入用户线程的 m_savepoints 链表的尾部。
server 层会创建一个SAVEPOINT 对象,用于存放 savepoint 信息。
binlog 会把binlog offset 写入 server 层为它分配的一块 8 字节的内存里。
InnoDB 会维护自己的 savepoint 链表,里面保存着trx_named_savept_t 对象。
如果 m_savepoints 链表中存在和本次创建的 savepoint 同名的 savepoint, 创建新的 savepoint 之前,server 层会从链表中删除这个同名的 savepoint。
server 层创建的 SAVEPOINT 对象会放入m_savepoints 链表的末尾。
InnoDB 创建的 trx_named_savept_t 对象会放入事务对象的trx_savepoints 链表的末尾。
MySQL:排序(filesort)详细解析(字长文)
MySQL排序详解:深入理解filesort过程(简化版)
MySQL中的排序(filesort)是DBA工作中常见的操作,本文主要针对Innodb引擎,使用5.7.源码版本,针对快速排序和归并排序进行详细解析。filesort在执行计划中表示排序操作,但执行计划本身并不揭示所有细节。
首先,我们从一个问题出发,介绍一个朋友遇到的案例,排序后临时文件意外达G。我们将通过实例逐步分析排序的流程。
1. 确认排序字段:从order by语句开始,如"a2,a3",并存储在Filesort的sortorder中,涉及原始和修改的filesort算法,但本文不涉及复杂算法分支。
2. 计算sort字段长度:通过sortlength函数,考虑每个字段的长度,如varchar(),长度计算为字符数量的两倍。超过max_sort_length设置的字段将导致排序精度下降。
3. 确定addon字段空间:根据max_length_for_sort_data,判断是否使用回表排序算法。如a1、a2、a3都是需要的字段,且总长度超过字节,会使用回表排序。
4. 计算每行数据长度:考虑sort字段和addon字段,包括可能的打包压缩。在内存排序阶段,将数据按照计算出的长度存储。
5. 分配内存:根据sort_buffer_size和表大小,计算实际需要的内存,并进行内存排序。
6. 内存排序与外部归并:如果数据量大,内存排序后会写入临时文件,进行外部归并排序。
7. 排序方式总结:文件sort函数会输出排序方式,如sort_key+packed_additional_fields(不回表排序,打包字段)或sort_key+additional_fields(固定长度字段)。
8. 最终排序:可能生成额外的临时文件,存储归并排序结果,文件数量根据排序量变化。
9. 问题:original filesort算法的回表和Rows_examined的计算。
. 使用OPTIMIZER_TRACE查看排序结果,理解排序过程和使用的内存。
案例中,通过group by操作的排序,如果sort字段过大,会使用回表排序,导致临时文件占用巨大。总结排序过程包括了组织排序数据的方式、排序方法的选择、内存分配策略以及临时文件的管理。
理解排序过程对优化查询性能和避免大文件临时文件至关重要。通过合理设计和使用索引,以及优化排序策略,可以有效控制临时文件的大小。
故障分析 | 从 Insert 并发死锁分析 Insert 加锁源码逻辑
死锁是数据库并发操作中的常见问题,涉及业务关联、机制复杂、类型多样等特点,给分析带来了挑战。本文以MySQL数据库中并发Insert导致死锁为例,通过问题发现、重现、根因分析和解决策略,提供一套科学有效的死锁处理方案。文章首先概述了死锁的基本现象和常见特性,指出死锁触发原因与应用逻辑相关,且涉及多个事务。由于不同数据库的锁实现机制差异,分析死锁问题往往不易。接着,文章详细描述了死锁问题的实例,包括日志提示、innodb status输出和事务执行过程。通过与研发团队的沟通和问题复现,文章进一步分析了事务之间的锁等待和持有状态,提出了问题的具体原因。为解决死锁问题,文章提出了优化唯一索引和调整并发策略的建议,并结合MySQL的锁实现机制,通过源码分析揭示了死锁产生的根本原因。最终,文章总结了避免死锁的关键措施,包括选择适合的隔离级别、减少对Unique索引的依赖,并通过性能数据追踪和源码理解来有效诊断和解决死锁问题。文章旨在为数据库运维人员提供一套实用的死锁处理方法,促进数据库系统稳定性和性能优化。
慢查询日志中的 Lock_time 从哪里来?
在探讨慢查询日志中的 Lock_time 时,首先要了解的是,与这位老相识的关联并不仅限于它表示锁等待时间这一层面,而是深入理解 Lock_time 的构成以及它是如何被计算得出的。
深入研究 Lock_time 之前,我们仅知其代表锁等待时间,却未探入其具体组成与计算过程。在众多 SQL 执行时间较长的场景中,我们时常困惑于 Lock_time 的数值似乎与其等待时间并不成正比,如观察到 Lock_time 仅为 0. 秒。
本文旨在揭开 Lock_time 的面纱,探索它包含的锁等待时间的来源以及计算方式。基于 MySQL 8.0. 源码,我们将重点放在 InnoDB 存储引擎上,通过分析其实现逻辑,以直观呈现 Lock_time 的组成与计算过程。
首先,明确 Lock_time 的计算方法。它由表锁等待时间和行锁等待时间两部分相加形成。这启示我们,对 Lock_time 的理解不仅限于表锁等待时间的考量,还需关注行锁等待时间的计算与累加。
在表锁等待时间的实现中,源码展示了从 Sql_cmd_dml::execute() 函数开始,到 lock_external() 方法的执行,整个过程涉及多个函数和调用,包括 lock_tables()、mysql_lock_tables() 等。这一系列操作最终在 thd->inc_lock_usec() 函数中实现了表锁等待时间的累积。
值得注意的是,表锁等待时间并非单纯反映锁等待过程,它还包含了执行一些初始化操作所需的时间,如同步刷脏页操作。对于 FLUSH TABLES ... WITH READ LOCK 语句,表锁等待时间更包含了将涉及的表所属表空间的脏页同步到磁盘所需的时间。
行锁等待时间的计算则更为直接,主要关注的是在加锁过程中记录的等待时间。通过 sel_set_rec_lock() 函数进行加锁操作,当其他事务持有该记录的行锁时,等待时间即开始计算。通过代码逻辑,我们可直观理解这一过程,即在获取行锁或等待超时后,通过当前时间减去开始时间计算得到行锁等待时间。
综上所述,Lock_time 由表锁与行锁等待时间共同构成,两者在累加的过程中最终形成 Lock_time。表锁等待时间不仅包含锁等待时间本身,还可能涉及额外的初始化操作时间,而行锁等待时间则更为直接且精确。通过深入分析源码,我们对 Lock_time 的构成有了更全面的理解。
MySQL的三种模式简介mysql三种模式
MySQL的三种模式简介
MySQL 是一种开放源代码的关系型数据库管理系统,可用于处理大量数据。MySQL的三种模式是:MyISAM、InnoDB 和 MEMORY。这些模式具有不同的特性和用途,因此在选择模式时应了解其优缺点。
1. MyISAM模式
MyISAM 是 MySQL 最常用的模式之一,它最适用于读操作较多的系统。MyISAM 对于大量的读操作具有良好的表现,但不够适合写入频率很高的应用程序。
下面是使用 MyISAM 模式创建一张表的示例:
CREATE TABLE `mytable` (
`id` int() NOT NULL AUTO_INCREMENT,
`name` varchar() NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
2. InnoDB 模式
InnoDB 是 MySQL 模式中的另一个流行选项。它适用于需要频繁写入的应用程序场景。InnoDB 是一个支持事务处理、外键约束和异常处理的存储引擎。它还支持行级锁定,这意味着多个用户可以同时访问同一数据表,而不会产生冲突。
下面是使用 InnoDB 模式创建一张表的示例:
CREATE TABLE `mytable` (
`id` int() NOT NULL AUTO_INCREMENT,
`name` varchar() NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3. MEMORY 模式
MEMORY 模式是 MySQL 中的一种高速缓存存储引擎。与 MyISAM 和 InnoDB 不同,MEMORY 模式将数据存储在 RAM 中,而不是硬盘。这使得存储和检索数据的速度非常快,但是,当系统发生崩溃或服务器被关闭时,数据将会丢失。
下面是使用 MEMORY 模式创建一张表的示例:
CREATE TABLE `mytable` (
`id` int() NOT NULL AUTO_INCREMENT,
`name` varchar() NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MEMORY DEFAULT CHARSET=utf8;
结论
在选择MySQL模式时,要根据应用的性质和需求来选择。如果很少进行写操作,可以使用 MyISAM,如果需要处理大量事务,可以选择 InnoDB。如果需要处理临时数据,可以使用 MEMORY 存储引擎。
MySQL模式的选择改变了 MySQL 服务器的性能和特性。在实施 MySQL 数据库时,应始终选择最适合应用程序的存储引擎。