打开order by的大门,一探究竟《死磕MySQL系列 十二》(1)

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 打开order by的大门,一探究竟《死磕MySQL系列 十二》

在日常开发工作中,你一定会经常遇到要根据指定字段进行排序的需求。


这时,你的SQL语句类似这样。


select id,phone,code from evt_sms where phone like '13020%' order by id desc limit 10


这个SQL的逻辑是十分清晰明了,但其内部的执行原理你知多少。


接下来,本期文章将带你打开order by的大门一探究竟。


本期所有结论都基于MySQL8.0.26版本


一、常见的Extra几个信息

在MySQL中想看一条SQL的性能不仅仅看是否用上了索引,还要看Extra中的内容,以下内容来自官方文档,给你最准确的学习资料。


using index


根据索引树可直接检索列信息,无需额外的操作来读取实际的行。


索引列即为查询列,也为条件列。


using index condition


下面这条语句name为普通索引,age无索引。


select * from table where name = ? and age = ?


索引下推是在MySQL5.6及以后的版本出现的。


之前的查询过程是,先根据name在存储引擎中获取数据,然后在根据age在server层进行过滤。


在有了索引下推之后,查询过程是根据name、age在存储引擎获取数据,返回对应的数据,不再到server层进行过滤。


当你使用Explain分析SQL语句时,如果出现了using index condition那就是使用了索引下推,索引下推是在组合索引的情况出现几率最大的。


using index for group_by


只查索引列,对索引列使用了group by


explain select phone from evt_sms where phone = "13054125874" group by phone;


using where


查询的列被索引覆盖,并且where筛选条件是索引列之一,但不是索引的前导列,Extra中为Using where; Using index,

意味着无法直接通过索引查找来查询到符合条件的数据


查询的列被索引覆盖,并且where筛选条件是索引列前导列的一个范围,同样意味着无法直接通过索引查找查询到符合条件的数据


zero limit


这个估计很少有小伙伴知道,就是你的SQL语句查询数量为limit 0


using temporary


使用了临时表,一般在使用group by、order by时会遇到。


这个也是本文即将要聊的话题。


using filesort


一般在使用group by、order by时会遇到,排序过程在内存中完成


Backward index scan


对索引列使用了降序操作


这里只列举了最常见的几个信息,MySQL官方文档中对Extra的解析大概有37个,感兴趣的可以去看看,后期咔咔也会逐步完善这块内容。


二、文件排序

由于是在一些统计、排序的业务中会经常见到Extra中出现using filesort的信息。


在MySQL8.0.26版本中对一个没有索引的列进行排序在Extra中显示using filesort。在低版本中需要你进行试验在什么情况下会出现。


image.png


在Extra中显示的using filesort表示的就是排序,MySQL会给每个线程分配一块内存用于排序,也被称之为sort_buffer。这期文章和下期文章会牵扯到很多名词,记得自己整理一下哈!


再看这条语句


image.png


那么这条SQL执行的具体流程是什么呢?


1、初始化sort_buffer,放入字段phone、code字段


2、在phone的索引树找到主键值


3、根据主键值到主键索引树中检索处phone、code对应字段的值,再存储sort_buffer中


4、继续从phone取下一个主键值


5、重复第三、第四,直到不满足phone = 条件为止


6、在sort_buffer中的数据按照字段phone做快排


7、按照快排的结果取出前10行返回改客户端即可


问题:所有的排序都是在内存中进行的?


当然不是,任何内存都不是无限制的,是否在内存中排序取决于MySQL参数sort_buffer_sort。


image.png


在MySQL8.0.26版本中这个值大小默认为256kb。


当需要排序的数据量大于256kb的阀值时,则会利用临时文件进行辅助排序,也就是常说的归并排序算法实现。


sort_buffer_size跟需要临时文件的个数成正比,如果sort_buffer_size越小则临时文件的数量就越多。


如何查看一个排序是否使用了临时文件,这个答案就交给大家来实现,版本不一致会导致很多结果都不同。


问题:你知道归并排序是如何实现的吗?


现在你知道了如果排序的数据大于sort_buffer_size会使用临时文件排序,这种排序使用的就是归并排序的思想,接下来让我们看看具体的流程是怎么样的。


1、把需要排序的数据分割,分割成每块数据都可以存放到sort_buufer中


2、对每块数据在sort_buufer中进行排序,排序好后,写入某个临时文件


3、当所有的数据都写入临时文件后,这时对于每个临时文件内部来说是有序的,但对于所有临时文件是无序的,所以还需要合并数据


4、假设现在存在tmp1和tmp2两个临时文件,这时分别从tmp1、tmp2读入部分数据到内存


5、假设从tmp1和tmp2中分别读入[0-5]的数据,然后分别使用tmp1[0]、tmp2[0] 进行对比,一直到tmp1[5]、tmp2[5],这样两两比较就可以把tmp1、tmp2合并为一个文件。经过几轮下来所有分割的数据都会合并为一个有序的大文件


三、文件排序很慢,还有其它办法吗

通过上面的案例,如果排序的数据量非常大则会超过sort_buffer_size的最大值,就只能使用文件排序,文件排序涉及了多次的文件合并是非常消耗性能的。


在上文你有没有发现一个细节,SQL中只需要排序code字段,但把phone字段也加到了sort_buufer中了。


这样单行的数据大小无形中就增大了,这样内存中能够存放的行数就减少了,需要分割成多个临时文件,排序性能会很差,那么有没有其它方案可以解决这种问题呢?


答案是肯定有的,就是接下来要聊的rowid排序。


先看一个参数max_length_for_sort_data


image.png


默认max_length_for_sort_data的大小为4096字节,假设现在要排序的数据非常多,我们可以修改这个参数让其使用rowid的算法。


MySQL中专门控制用户排序的行数据长度的参数,如果单行的数据长度超过了这个值,则MySQL会自动更换为rowid算法。


rowid排序的思想就是把不需要的数据不放到sort_buufer中,让sort_buffer中只存放需要排序的字段。


问题:如果你是设计者,你会存放那些字段


假设现在存放只需要排序的字段,排序很快完成了,拿到排序后的数据结果你应该怎么办呢?你已经无从下手了。


因此,你可以把主键ID的值也存放到sort_buufer中,当排序完成后通过ID回表即可得到排序后的数据。


执行流程


试想一下,这个执行流程其实跟文件排序的流程大差不差。


只是存放到sort_buufer中的字段变为需要排序的字段加上主键字段。


接着在sort_buufer中按照排序字段进行排序


最后再遍历排序结果,取需要的行数,并使用id进行回表一次,查出你需要的列即可。


注意点


这不是说使用了rowid的排序算法后就不使用临时文件排序了,不是这样的。


使用rowid只是存放到sort_buffer中的数据多个,若需要排序的数据很多还是需要使用临时文件的。



相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
4月前
|
SQL 关系型数据库 MySQL
MySQL ORDER BY(排序) 语句
MySQL ORDER BY(排序) 语句
|
SQL 关系型数据库 MySQL
mysql ORDER BY自定义排序
mysql ORDER BY自定义排序
271 0
mysql ORDER BY自定义排序
|
SQL 关系型数据库 MySQL
MySQL排序ORDER BY与分页LIMIT,SQL,减少数据表的网络传输量,完整详细可收藏
MySQL排序ORDER BY与分页LIMIT,SQL,减少数据表的网络传输量,完整详细可收藏
106 0
|
关系型数据库 MySQL
朴实!简单!依你所好,MySQL排序查询ORDER BY
朴实!简单!依你所好,MySQL排序查询ORDER BY
90 0
|
SQL 关系型数据库 MySQL
MYSQL中ORDER BY(排序查询)
`[NOT] ORDER BY 字段1[ASC/DESC], 字段2[[ASC/DESC] ] ……` `ASC`表示升序,`DESC`表示降序 如果不写,默认为升序
110 0
MYSQL中ORDER BY(排序查询)
|
算法 关系型数据库 MySQL
【MySQL笔记】ORDER BY是如何工作的?
每次业务功能中总有按操作时间排序,或者按其他字段排序的需求,一想到排序我们就会想到MySQL中的ORDER BY,那在使用的过程中,我们是否会存在不合理的使用导致查询的速度下降呢?
|
SQL 关系型数据库 MySQL
深聊MySQL,从入门到入坟之:如何让order by、group by查询速度飞起来
深聊MySQL,从入门到入坟之:如何让order by、group by查询速度飞起来
99 0
深聊MySQL,从入门到入坟之:如何让order by、group by查询速度飞起来
|
关系型数据库 MySQL 数据库
【黄啊码】MySQL入门—5、数据库小技巧:单个列group by就会,多个列呢?
【黄啊码】MySQL入门—5、数据库小技巧:单个列group by就会,多个列呢?
93 0
【黄啊码】MySQL入门—5、数据库小技巧:单个列group by就会,多个列呢?
|
关系型数据库 MySQL
MySQL - Group By 1
MySQL - Group By 1
78 0
|
17天前
|
关系型数据库 MySQL 数据库
mysql卸载、下载、安装(window版本)
mysql卸载、下载、安装(window版本)