欢迎来到皮皮网网首页

【oppo源码输出】【开源博客网站源码】【如何看servlet源码】innodb源码解析

来源:now场控源码 时间:2024-11-25 08:14:52

1.MySQL 核心模块揭秘 | 12 期 | 创建 savepoint
2.生产问题(三)Mysql for update 导致大量行锁
3.Mysql InnoDB和MyISAM的区别
4.慢查询日志中的源码 Lock_time 从哪里来?
5.MySQL全文索引源码剖析之Insert语句执行过程
6.MySQL 核心模块揭秘 | 13 期 | 回滚到 savepoint

innodb源码解析

MySQL 核心模块揭秘 | 12 期 | 创建 savepoint

       回滚操作,除了回滚整个事务,解析还可以部分回滚。源码部分回滚,解析需要保存点(savepoint)的源码协助。本文我们先看看保存点里面都有什么。解析oppo源码输出

       作者:操盛春,源码爱可生技术专家,解析公众号『一树一溪』作者,源码专注于研究 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,如何看servlet源码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 层会从链表中删除这个同名的如何下载bt源码 savepoint。

       server 层创建的 SAVEPOINT 对象会放入m_savepoints 链表的末尾。

       InnoDB 创建的 trx_named_savept_t 对象会放入事务对象的trx_savepoints 链表的末尾。

生产问题(三)Mysql for update 导致大量行锁

       在一次复盘会上,我的同事分享了一次因误用了 Mysql 的 for update 命令,导致大量行锁产生的问题。这一情况引起了我的深思,因为在网上广泛流传的观点认为 InnoDB 存在锁升级,表锁的产生与数据量、锁的类型有关。然而,这一观点基于对《高性能 Mysql》和《Innodb 存储引擎》的深入理解,实则存在误解。

       在环境设定为 Mysql5.7,隔离级别为 RC 的情况下,我发现 for update 一个不存在的 where 条件时,InnoDB 加的是 Record 级别的锁。这一点通过执行查询信息得到验证,信息显示两个事务加的都是行级别锁。

       对于锁住的行数量与数据的准确性,我注意到在相关书籍中提到的锁数据统计方式可能不够精确。而当 for update 命令无法根据索引加锁时,InnoDB 实际上会在行数据中进行搜索,并对主键进行加锁,而不是整个表。这种设计的初衷可能是为了提升效率,但具体设计考虑则无从得知。

       在 InnoDB 加锁机制中,锁的获取遵循从上至下的逻辑,即自动加锁只包括表级别的意向锁和行级锁。表级别的意向锁仅阻塞全表扫描,不会影响其他操作。在 RR 隔离级别下,InnoDB 会采取 GapLock 和 Next-keyLock 算法,以防止插入数据导致的幻读问题,但这一操作并非绝对,对于唯一索引而言,InnoDB 可能会降低级别使用行级锁,学校文件管理 源码避免锁住范围。

       总结来看,基于对实际操作的验证和对权威书籍的理解,可以得出以下

在 RC 级别下,InnoDB 的加锁机制主要为行级锁,表级的意向锁仅阻塞全表扫描。InnoDB 并不存在锁升级的现象。当 for update 命令未能通过索引加锁时,InnoDB 会在行数据中对主键进行加锁。

       通过这一分析,我与 DBA 进行了深入讨论,对这些观点进行了确认。对于这一问题,我鼓励大家在实际操作、阅读权威书籍和源码时,保持批判性思考,避免盲从网上信息。书籍与源码的阅读应结合实际经验,因为个人理解能力的差异可能导致理解方向的偏差。

       原创声明:

       本文章由我独立创作,内容均为原创。

       如有需要转载或使用本文章内容,请注明出处。

Mysql InnoDB和MyISAM的区别

       ã€€ã€€InnoDB和MyISAM是在使用MySQL最常用的两个表类型,各有优缺点,视具体应用而定。基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。

       ã€€ã€€MyIASM是IASM表的新版本,有如下扩展:

       ã€€ã€€äºŒè¿›åˆ¶å±‚次的可移植性。

       ã€€ã€€NULL列索引。

       ã€€ã€€å¯¹å˜é•¿è¡Œæ¯”ISAM表有更少的碎片。

       ã€€ã€€æ”¯æŒå¤§æ–‡ä»¶ã€‚

       ã€€ã€€æ›´å¥½çš„索引压缩。

       ã€€ã€€æ›´å¥½çš„键吗统计分布。

       ã€€ã€€æ›´å¥½å’Œæ›´å¿«çš„auto_increment处理。

       ã€€ã€€ä»¥ä¸‹æ˜¯ä¸€äº›ç»†èŠ‚和具体实现的差别:

       ã€€ã€€1.InnoDB不支持FULLTEXT类型的索引。

       ã€€ã€€2.InnoDB中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语句包含where条件时,两种表的操作是一样的。

       ã€€ã€€3.对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。

       ã€€ã€€4.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。

       ã€€ã€€5.LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。

       ã€€ã€€å¦å¤–,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like “%aaa%”

       ã€€ã€€ä»»ä½•ä¸€ç§è¡¨éƒ½ä¸æ˜¯ä¸‡èƒ½çš„,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势.

       ã€€ã€€

       ã€€ã€€MySQL中MyISAM引擎与InnoDB引擎性能简单测试

       ã€€ã€€[硬件配置]

       ã€€ã€€CPU : AMD+ (1.8G)

       ã€€ã€€å†…å­˜: 1G/现代

       ã€€ã€€ç¡¬ç›˜: G/IDE

       ã€€ã€€[软件配置]

       ã€€ã€€OS : Windows XP SP2

       ã€€ã€€SE : PHP5.2.1

       ã€€ã€€DB : MySQL5.0.

       ã€€ã€€Web: IIS6

       ã€€ã€€[MySQL表结构]

       ã€€ã€€CREATE TABLE `myisam` (

       ã€€ã€€`id` int() NOT NULL auto_increment,

       ã€€ã€€`name` varchar() default NULL,

       ã€€ã€€`content` text,

       ã€€ã€€PRIMARY KEY (`id`)

       ã€€ã€€) ENGINE=MyISAM DEFAULT CHARSET=gbk;

       ã€€ã€€CREATE TABLE `innodb` (

       ã€€ã€€`id` int() NOT NULL auto_increment,

       ã€€ã€€`name` varchar() default NULL,

       ã€€ã€€`content` text,

       ã€€ã€€PRIMARY KEY (`id`)

       ã€€ã€€) ENGINE=InnoDB DEFAULT CHARSET=gbk;

       ã€€ã€€[数据内容]

       ã€€ã€€$name = "heiyeluren";

       ã€€ã€€$content = "MySQL支持数个存储引擎作为对不同表的类型的处理器。MySQL存储引擎包括处理事务安全表的引擎和处理非事务安全表的引擎:· MyISAM管理非事务表。它提供高速存储和检索,以及全文搜索能力。MyISAM在所有MySQL配置里被支持,它是默认的存储引擎,除非你配置MySQL默认使用另外一个引擎。 ·MEMORY存储引擎提供“内存中”表。MERGE存储引擎允许集合将被处理同样的MyISAM表作为一个单独的表。就像MyISAM一样,MEMORY和MERGE存储引擎处理非事务表,这两个引擎也都被默认包含在MySQL中。 释:MEMORY存储引擎正式地被确定为HEAP引擎。· InnoDB和BDB存储引擎提供事务安全表。BDB被包含在为支持它的操作系统发布的MySQL-Max二进制分发版里。InnoDB也默认被包括在所有MySQL 5.1二进制分发版里,你可以按照喜好通过配置MySQL来允许或禁止任一引擎。·EXAMPLE存储引擎是一个“存根”引擎,它不做什么。你可以用这个引擎创建表,但没有数据被存储于其中或从其中检索。这个引擎的目的是服务,在MySQL源代码中的一个例子,它演示说明如何开始编写新存储引擎。同样,它的主要兴趣是对开发者。";

       ã€€ã€€[插入数据-1] (innodb_flush_log_at_trx_commit=1)

       ã€€ã€€MyISAM 1W:3/s

       ã€€ã€€InnoDB 1W:/s

       ã€€ã€€MyISAM W:/s

       ã€€ã€€InnoDB W:/s

       ã€€ã€€MyISAM W:/s

       ã€€ã€€InnoDB W:没敢测试

       ã€€ã€€[插入数据-2] (innodb_flush_log_at_trx_commit=0)

       ã€€ã€€MyISAM 1W:3/s

       ã€€ã€€InnoDB 1W:3/s

       ã€€ã€€MyISAM W:/s

       ã€€ã€€InnoDB W:/s

       ã€€ã€€MyISAM W:/s

       ã€€ã€€InnoDB W:/s

       ã€€ã€€[插入数据3] (innodb_buffer_pool_size=M)

       ã€€ã€€InnoDB 1W:3/s

       ã€€ã€€InnoDB W:/s

       ã€€ã€€InnoDB W:/s

       ã€€ã€€[插入数据4] (innodb_buffer_pool_size=M, innodb_flush_log_at_trx_commit=1, set autocommit=0)

       ã€€ã€€InnoDB 1W:3/s

       ã€€ã€€InnoDB W:/s

       ã€€ã€€InnoDB W:/s

       ã€€ã€€[MySQL 配置文件] (缺省配置)

       ã€€ã€€# MySQL Server Instance Configuration File

       ã€€ã€€[client]

       ã€€ã€€port=

       ã€€ã€€[mysql]

       ã€€ã€€default-character-set=gbk

       ã€€ã€€[mysqld]

       ã€€ã€€port=

       ã€€ã€€basedir="C:/mysql/"

       ã€€ã€€datadir="C:/mysql/Data/"

       ã€€ã€€default-character-set=gbk

       ã€€ã€€default-storage-engine=INNODB

       ã€€ã€€sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"

       ã€€ã€€max_connections=

       ã€€ã€€query_cache_size=0

       ã€€ã€€table_cache=

       ã€€ã€€tmp_table_size=M

       ã€€ã€€thread_cache_size=8

       ã€€ã€€myisam_max_sort_file_size=G

       ã€€ã€€myisam_max_extra_sort_file_size=G

       ã€€ã€€myisam_sort_buffer_size=M

       ã€€ã€€key_buffer_size=M

       ã€€ã€€read_buffer_size=K

       ã€€ã€€read_rnd_buffer_size=K

       ã€€ã€€sort_buffer_size=K

       ã€€ã€€innodb_additional_mem_pool_size=4M

       ã€€ã€€innodb_flush_log_at_trx_commit=1

       ã€€ã€€innodb_log_buffer_size=2M

       ã€€ã€€innodb_buffer_pool_size=M

       ã€€ã€€innodb_log_file_size=M

       ã€€ã€€innodb_thread_concurrency=8

       ã€€ã€€ã€æ€»ç»“】

       ã€€ã€€å¯ä»¥çœ‹å‡ºåœ¨MySQL 5.0里面,MyISAM和InnoDB存储引擎性能差别并不是很大,针对InnoDB来说,影响性能的主要是 innodb_flush_log_at_trx_commit 这个选项,如果设置为1的话,那么每次插入数据的时候都会自动提交,导致性能急剧下降,应该是跟刷新日志有关系,设置为0效率能够看到明显提升,当然,同样你可以SQL中提交“SET AUTOCOMMIT = 0”来设置达到好的性能。另外,还听说通过设置innodb_buffer_pool_size能够提升InnoDB的性能,但是我测试发现没有特别明显的提升。

       ã€€ã€€åŸºæœ¬ä¸Šæˆ‘们可以考虑使用InnoDB来替代我们的MyISAM引擎了,因为InnoDB自身很多良好的特点,比如事务支持、存储过程、视图、行级锁定等等,在并发很多的情况下,相信InnoDB的表现肯定要比MyISAM强很多,当然,相应的在my.cnf中的配置也是比较关键的,良好的配置,能够有效的加速你的应用。

       ã€€ã€€å¦‚果不是很复杂的Web应用,非关键应用,还是可以继续考虑MyISAM的,这个具体情况可以自己斟酌。

慢查询日志中的 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全文索引源码剖析之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缓存。事务提交阶段对文档进行分词,获取{ 单词,(文档,偏移)}关联对,并插入到cache。刷脏阶段后台线程将cache刷新到磁盘。

       全文索引的并发插入可能导致OOM问题,可通过修复patch #解决。当MySQL进程崩溃时,fts_init_index函数会恢复crash前的cache数据。

MySQL 核心模块揭秘 | 期 | 回滚到 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:排序(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字段过大,会使用回表排序,导致临时文件占用巨大。总结排序过程包括了组织排序数据的方式、排序方法的选择、内存分配策略以及临时文件的管理。

       理解排序过程对优化查询性能和避免大文件临时文件至关重要。通过合理设计和使用索引,以及优化排序策略,可以有效控制临时文件的大小。