MySQL——优化ORDER BY语句
本篇文章我们将了解ORDER BY语句的优化,在此之前,你需要对索引有基本的了解,不了解的朋友们可以先看一下我之前写过的索引相关文章。现在让我们开始吧。
MySQL中的两种排序方式
1.通过有序索引顺序扫描直接返回有序数据
因为索引的结构是B+树,索引中的数据是按照一定顺序进行排列的,所以在排序查询中如果能利用索引,就能避免额外的排序操作。EXPLAIN分析查询时,Extra显示为Using index。
2.Filesort排序,对返回的数据进行排序
所有不是通过索引直接返回排序结果的操作都是Filesort排序,也就是说进行了额外的排序操作。EXPLAIN分析查询时,Extra显示为Using filesort。
ORDER BY优化的核心原则
尽量减少额外的排序,通过索引直接返回有序数据。
ORDER BY优化实战
用于实验的customer表的索引情况:

首先要注意:
MySQL一次查询只能使用一个索引,如果要对多个字段使用索引,建立复合索引。
ORDER BY优化
1.查询的字段,应该只包含此次查询使用的索引字段和主键,其余的非索引字段和索引字段作为查询字段则不会使用索引。
只查询用于排序的索引字段,可以利用索引排序:
explain select store_id,email from customer order by store_id,email;

但是要注意,排序字段在多个索引中,无法使用索引排序,查询一次只能使用一个索引:
explain select store_id,email,last_name from customer order by store_id,email,last_name;

只查询用于排序的索引字段和主键,可以利用索引排序:
画外音:MySQL默认的InnoDB引擎在物理上采用聚集索引这种方式,按主键进行搜索,所以InnoDB引擎要求表必须有主键,即使没有显式指定主键,InnoDB引擎也会生成唯一的隐式主键,也就是说索引中必定有主键。
explain select customer_id,store_id,email from customer order by store_id,email;

查询用于排序的索引字段和主键之外的字段,不会利用索引排序:
explain select store_id,email,last_name from customer order by store_id,email;

explain select * from customer order by store_id,email;

WHERE + ORDER BY 优化
1.排序字段在多个索引中,无法利用索引排序
排序字段在多个索引(不在同一个索引)中,无法利用索引排序:
explain select * from customer where last_name='swj' order by last_name,store_id;

画外音:当排序字段不在同一个索引时,无法满足在一颗B+树中完成排序,必须再进行一次额外的排序
排序字段在一个索引中,并且WHERE条件和ORDER BY使用相同的索引,可以利用索引排序:
explain select * from customer where last_name='swj' order by last_name;

当然组合索引也可以利用索引排序:
注意字段store_id,email在一个组合索引中
explain select * from customer where store_id = 5 order by store_id,email;

2.排序字段顺序与索引列顺序不一致,无法利用索引排序
画外音:这条是针对组合索引而言的,我们都知道使用组合索引必要要遵循最左原则,WHERE子句必须有索引中第一列,虽然ORDER BY子句没有这个要求,但是也要求排序字段顺序和组合索引列顺序匹配。我们平常在使用组合索引的时候,一定要养成按照组合索引列顺序书写的好习惯。
排序字段顺序与索引列顺序不一致,无法利用索引排序:
explain select * from customer where store_id > 5 order by email,store_id;

应该确保排序字段顺序与索引列顺序一致,这样可以利用索引排序:
explain select * from customer where store_id > 5 order by store_id,email;

ORDER BY子句不要求必须索引中第一列,没有仍然可以利用索引排序。但是有个前提条件,只有在等值过滤时才可以,范围查询时不可以:
explain select * from customer where store_id = 5 order by email;

explain select * from customer where store_id > 5 order by email;

画外音:
其原因其实也很简单,范围查询时,第一列a肯定是排序好的(默认是升序),而第二个字段b其实就不是排序的了。但是如果a字段有相同的值时,那么b字段就是排序的了。所以如果是范围查询,就只能对b做一次额外的排序。
3.升降序不一致,无法利用索引排序
ORDER BY排序字段要么全部正序排序,要么全部倒序排序,否则无法利用索引排序。
explain select * from customer where store_id > 5 order by store_id,email;

explain select * from customer where store_id > 5 order by store_id desc,email desc;

explain select * from customer where store_id > 5 order by store_id desc,email asc;

总结:
上面的优化其实可以汇总为:WHERE条件和ORDER BY使用相同的索引,并且ORDER BY的顺序和索引顺序相同,并且ORDER BY的字段都是升序或者降序。否则肯定需要额外的排序操作,就会出现Filesort。
Filesort优化
通过创建合适的索引能够减少Filesort的出现,但是在某些情况下,无法完全让Filesort消失,此时只能想办法加快Filesort的操作。
Filesort的两种排序算法:
1.两次扫描算法
首先根据条件取出排序字段和行指针信息,之后在排序区sort buffer中排序。这种排序算法需要访问两次数据,第一次获取排序字段和行指针信息,第二次根据行指针获取记录,第二次读取操作可能会导致大量随即I/O操作。优点是排序的时候内存开销较小。
2.一次扫描算法
一次性取出满足条件的行的所有字段,然后在排序区sort buffer中排序后直接输出结果集。排序的时候内存开销比较大,但是排序效率比两次扫描算法要高。
根据两种排序算法的特性,适当加大系统变量max_length_for_sort_data的值,能够让MySQL选择更优化的Filesort排序算法。并且在书写SQL语句时,只使用需要的字段,而不是SELECT * 所有的字段,这样可以减少排序区的使用,提高SQL性能。
参考
《深入浅出MySQL》
推荐阅读
MySQL——通过EXPLAIN分析SQL的执行计划
MySQL——索引基础
MySQL——索引优化实战
数据库索引背后的数据结构
是什么影响了数据库索引选型?

MySQL——优化ORDER BY语句的更多相关文章
- MySQL优化order by导致的 using filesort
using filesort 一般出现在 使用了 order by 语句当中. using filesort不一定引起mysql的性能问题.但是如果查询次数非常多,那么每次在mysql中进行排序,还是 ...
- mysql优化之SQL语句优化
Mysql优化是一个老生常谈的问题, 优化的方向也优化很多:从架构层;从设计层;从存储层;从SQL语句层; 今天讲解一下从SQL语句层: 这个部分是程序员最容易把控的地方,也是最容易忽视的地方. 一个 ...
- mysql优化和sql语句优化总结
mysql性能优化 1. EXPLAIN 你的 SELECT 查询.使用 EXPLAIN 关键字可以让你知道MySQL是如何处理你的SQL语句的.这可以帮你分析你的查询语句或是表结构的性能瓶颈. 2. ...
- 优化order by 语句
mysql 演示数据库:http://downloads.mysql.com/docs/sakila-db.zip mysql 中排序方式 有序索引顺序扫描直接返回有序数据 explain selec ...
- SQL性能优化-order by语句的优化
原文:http://bbs.landingbj.com/t-0-243203-1.html 在某些情况中,MySQL可以使用一个索引来满足ORDER BY子句,而不需要额外的排序.where条件和or ...
- MySQL如何利用索引优化ORDER BY排序语句
MySQL索引通常是被用于提高WHERE条件的数据行匹配或者执行联结操作时匹配其它表的数据行的搜索速度. MySQL也能利用索引来快速地执行ORDER BY和GROUP BY语句的排序和分组操作. 通 ...
- MySQL如何利用索引优化ORDER BY排序语句 【转载】
本文转载自:http://blog.csdn.net/ryb7899/article/details/5580624 .感谢相关作者. MySQL索引通常是被用于提高WHERE条件的数据行匹配或者执 ...
- MySQL如何利用索引优化ORDER BY排序语
MySQL索引通常是被用于提高WHERE条件的数据行匹配或者执行联结操作时匹配其它表的数据行的搜索速度. MySQL也能利用索引来快速地执行ORDER BY和GROUP BY语句的排序和分组操作. 通 ...
- Mysql 优化与测试
由于经常被抓取文章内容,在此附上博客文章网址:,偶尔会更新某些出错的数据或文字,建议到我博客地址 : --> 点击这里 以下的测试数据根据环境的不同所耗费的时间有所不同,例如我在腾讯云上的测试 ...
随机推荐
- Redis学习系列二之.Net开发环境搭建及基础数据结构String字符串
一.简介 Redis有5种基本数据结构,分别是string.list(列表).hash(字典).set(集合).zset(有序集合),这是必须掌握的5种基本数据结构.注意Redis作为一个键值对缓存系 ...
- Git for Windows之使用SSH协议开通公钥免密登陆功能
1.删除Https的通信方式,建立SSH的通信方式 (1).查看当前的通信方式 当前是使用Https的方式与远程仓库进行通信 (2).删除HTTPS的通信方式 ok,HTTPS通信方式已删除 (3). ...
- jieba分词(1)
近几天在做自然语言处理,看了一篇论文:面向知识库的中文自然语言问句的语义理解,里面提到了中文的分词,大家都知道对于英文的分词,NLTK有很好的支持,但是NLTK对于中文的分词并不是很好(其实也没有怎么 ...
- 记一次使用mybatis进行like 模糊查询遇到的问题
"bdate like '#{date}%' and ..." 最开始这样写的· 将传入的参数和%用单引号包起来,但是这会报错 java.sql.SQLException: Par ...
- java学习-http中get请求的非ascii参数如何编码解码探讨
# 背景: 看着别人项目代码看到一个PathUtils工具类, 里面只有一个方法,String rebuild(String Path),将路径进行URLDecoder.decode解码,避免路径中 ...
- Docker Spring-boot
docker 1.使用 sudo 或 root 权限登录 Centos. 2.确保 yum 包更新到最新. $ sudo yum update 3.执行 Docker 安装脚本. $ curl -fs ...
- 一次Linux服务器被入侵和删除木马程序的经历
转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://wzlinux.blog.51cto.com/8021085/1740113 一.背景 晚上看到有台服 ...
- 腾讯、百度、网易游戏、华为Offer及笔经面经
原文出处:http://bbs.yingjiesheng.com/forum.php?mod=viewthread&tid=1011893&fromuid=1745894 应届生上泡了 ...
- new Thread与线程创建
概要:new Thread 并不意味着已经创建了一个线程,只能说明创建一个类的对象实例而已.而真正创建线程的是start()方法,此方法将调用本地方法start0()创建本地线程,而Thread的ru ...
- CustomSqlSessionFactoryBean
import java.io.File; import java.net.JarURLConnection; import java.net.URL; import java.util.ArrayLi ...