MySQL order by与group by查询优化实现详解
作者:流烟默 发布时间:2024-01-24 23:27:48
前言
order by满足两种情况,会使用 index 方式排序:
order by语句使用索引最左前列(最左匹配法则)
where子句和order by子句条件列组合满足最左匹配法则(where条件使用索引的最左前缀为常量)
下面给出几个实例来说明,如下所示我们创建表并为其创建组合索引(c1,c2,c3)。
CREATE TABLE `testc` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`c1` varchar(100) DEFAULT NULL,
`c2` varchar(100) DEFAULT NULL,
`c3` varchar(100) DEFAULT NULL,
`c4` varchar(100) DEFAULT NULL,
`c5` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `testc_c1_IDX` (`c1`,`c2`,`c3`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
where与order by满足最左匹配法则
# c1 c2满足最左匹配法则
explain select * from testc where c1='a1' order by c2
# 与上面等价
explain select * from testc where c1='a1' order by c2,c3
key_len
标明查找用到了索引 c1
,Extra中是Using index condition
没有同时出现using where ,表明 c2 索引用来读取数据而非执行查找动作。
MySQL Innodb下的B+树本身就是多路平衡树,那么索引换句话就是排好序的快速查找数据结构。如果order by用到了索引且排序和索引次序一样,那么无疑效果是最好的。
中间断裂
如下所示,缺少了c2,order by不满足最左匹配法则。
explain select * from testc where c1='a1' order by c3
可以看到Extra中Using index condition; Using filesort
说明虽然where可以用到索引(单独c1满足最左匹配),但是排序不满足,故而出现了filesort。
大哥不在
如下c1不在,那么很显然无论查找还是排序都用不到索引。
explain select * from testc where c2='a2' order by c3
这里Extra是Using where; Using filesort
,说明通过where子句过滤结果,然后对结果进行文件排序。
范围失效
如下所示,中间c2是个范围搜索,那么其后索引将失效也就是order by c3无法与where连接满足最左匹配法则。
explain select * from testc where c1='a1' and c2 > 'a2' order by c3
如下图所示,这里type = range
,ken_len表示用到了 c1,c2索引。Extra是Using index condition; Using filesort
表示查询用到了索引但是无法利用索引完成的排序操作。
这种情况如何优化呢?order by c2,c3
!这样就可以保证索引排序而不需要filesort。
explain select * from agriculture.testc where c1='a1' and c2 > 'a2'
order by c2,c3
order by 次序相反
如下所示,order by的次序没有与索引次序保持一致。这里Extra为Using index condition; Using filesort
。
explain select * from testc where c1='a1' order by c3,c2
覆盖索引
前面几个都是select *
,这里查找索引列。
没有where,order by满足全值匹配,select查询的数据是索引列。
explain select c1 from testc order by c1, c2,c3
这里Extra中只有Using index;
没有where,order by 大哥丢失,select查询的数据是索引列。
explain select c1 from testc order by c2,c3
这里Extra中是Using index; Using filesort
。
这里Extra信息为Using where; Using index; Using filesort
。
explain select c1 from testc where c1='a1' order by c3,c2
filesort的两种算法
filesort有两种机制:双路排序和单路排序。双路排序简单来讲就是两次扫描磁盘,最终得到数据。单路排序则是只需要读取一次,也就是一次磁盘IO。
双路排序
MySQL4.1之前是使用双路排序,读取行指针和order by列,对他们进行排序,然后扫描已经排序好的列表,按照列表中的值重新从列表中读取对应的数据输出(可以理解为从磁盘读取排序字段,在buffer进行排序,然后再从磁盘读取其他字段)。
取一批数据要进行两次磁盘IO,这是很耗时的。故而在MySQL4.1之后,出现了第二种改进的算法,也就是单路排序。
单路排序
从磁盘读取查询需要的所有列,按照order by列在buffer对它们进行排序,然后扫描排序后的列表进行输出。它的效率更快一点,避免了第二次读取数据,并且把随机IO变成了顺序IO。但是其会使用更多的空间,因为其缓存了数据在内存中。
单路的问题
可能取出的数据大小超过了sort_buffer的容量,导致每次只能取sort_buffer容量大小的数据进行排序(创建tmp文件,多路合并),排完再取sort_buffer容量大小…从而多次IO(可能比双路更多)。
可以尝试增大sort_buffer_size参数的设置或者max_length_for_sort_data参数的设置。
总结
order by时select * 是一个大忌,应该是查询需要的字段。
当query的字段大小总和小于max_length_for_sort_data而且排序字段不是text|blob类型时,会用改进后的算法–单路排序,否则使用双路排序。
两种算法的数据都有可能超出sort_buffer的容量,超出之后会创建tmp文件进行合并排序导致多次IO。尤其对于单路排序来说风险更大,所以需要适当调整sort_buffer的容量。
提高max_length_for_sort_data会增加使用单路排序算法的概率。但是如果设置的太高,数据总容量超过sort_buffer的概率就增大,明显症状是磁盘IO高,CPU使用率低。
group by
前面提到的规则针对group by均适用,group by 实质是先排序后分组,遵照索引建的最佳左前缀。当无法使用索引时,增大max_length_for_sort_data和sort_buffer参数的值。
需要注意的是where优先级高于having,能写在where限定的条件尽量不要通过having。
来源:https://janus.blog.csdn.net/article/details/126750827


猜你喜欢
- 前言前面我们已经介绍了 python面向对象入门教程之从代码复用开始(一) ,这篇文章主要介绍的是关于Python面向对象之设置对
- 此方法支持IE 不支持火狐。可能是因为FCKEidtor的keyup方法在火狐下不被支持。 FCKEditor编辑器换为TextBox,应该
- SMTPSMTP是发送邮件的协议,Python内置对SMTP的支持,可以发送纯文本邮件、HTML邮件以及带附件的邮件。Python对SMTP
- Neo4j是面向对象基于Java的 ,被设计为一个建立在Java之上、可以直接嵌入应用的数据存储。此后,其他语言和平台的支持被引入,Neo4
- 0x00 字符的编码计算机毕竟是西方国家的发明,最开始并没有想到会普及到全世界,只用一个字节中的7位(ASCII)来表示字符对于现在庞大的文
- 平方根,又叫二次方根,表示为〔√ ̄〕,如:数学语言为:√ ̄16=4。语言描述为:根号下16=4。以下实例为通过用户输入一个数字,并计算这个数
- 前言:之前博主分享过knockoutJS和BootstrapTable的一些基础用法,都是写基础应用,根本谈不上封装,仅仅是避免了html控
- Python自动的os库是和操作系统交互的库,常用的操作包括文件/目录操作,路径操作,环境变量操作和执行系统命令等。文件/目录操作获取当前目
- 前言tensorflow提供了多种读写方式,我们最常见的就是使用tf.placeholder()这种方法,使用这个方法需要我们提前处理好数据
- 前言十三届全国人大三次会议作了政府工作报告。这份政府工作报告仅有10500字左右,据悉是改革开放40年以来最短的一次。受到疫情影响,今年的两
- 本文实例讲述了python中__call__内置函数的用法。分享给大家供大家参考。具体分析如下:对象通过提供__call__(slef, [
- 定义:Dim MyArray() Redim MyArray(5)Session("StoredAr
- Pycharm代码运行调试,具体内容如下1、准备工作(1)Python版本为2.7或者更高版本(2)已经创建了一个Python工程并且添加了
- 本文实例讲述了Python实现的ftp服务器功能。分享给大家供大家参考,具体如下:python 具备强大的网络编程功能,而且代码简介,用简单
- Python的运算符和其他语言类似(我们暂时只了解这些运算符的基本用法,方便我们展开后面的内容,高级应用暂时不介绍)数学运算>>
- Python中专门提供了telnetlib库,用来完成基于telnet协议的通信功能。python3下使用telnetlib模块连接网络设备
- 锁有两种分类方法。(1) 从数据库系统的角度来看锁分为以下三种类型: •独占锁(Exclusive Lock)独占锁锁定的资源只允许进行锁定
- 内容摘要合理使用渐变留白网格布局提高字体应用明确而有效的导航设计漂亮、有用的页脚介绍优秀设计和卓越设计之间的区别是比较小的。一般人可能无法解
- Git是一个开源的分布式版本控制系统,用于高效的管理各种大小项目和文件。有着管理多样化、分享速度快、数据
- 前言密码安全是非常重要的,因此我们在代码中往往需要对密码进行加密,以此保证密码的安全加依赖<!-- jasypt --><