一、order by的原理

1、利用索引的有序性获取有序数据

当查询语句的 order BY 条件和查询的执行计划中所利用的 Index 的索引键(或前面几个索引键)完全一致,且索引访问方式为 range,ref 或者 index 的时候,MySQL 可以利用索引顺序而直接取得已经排好序的数据。这种方式的 order BY 基本上可以说是最优的排序方式了,因为 MySQL 不需要进行实际的排序操作,需要注意的是使用索引排序也有很多限制。

当对连接操作进行排序时,如果ORDER BY仅仅引用第一个表的列,MySQL对该表进行filesort操作,然后进行连接处理,此时,EXPLAIN输出“Using filesort”;否则,MySQL必须将查询的结果集生成一个临时表,在连接完成之后进行filesort操作,此时,EXPLAIN输出“Using temporary;Using filesort”。

注意:MySQL在查询时最多只能使用一个索引。因此,如果WHERE条件已经占用了索引,那么在排序中就不使用索引了

mysql> show create table test \G
*************************** 1. row ***************************
Table: test
Create Table: CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`addtime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`a` int(11) unsigned NOT NULL,
`b` int(11) unsigned NOT NULL,
`c` int(11) unsigned NOT NULL,
`data` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`addtime`,`a`,`b`),
KEY `a` (`a`),
KEY `b` (`b`),
KEY `c` (`c`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8

执行查询1

mysql> explain  select * from test where addtime='2015-10-13 15:38:32' order by  a , b ;
+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+
| 1 | SIMPLE | test | ref | u | u | 8 | const | 4 | Using where |
+----+-------------+-------+------+---------------+------+---------+-------+------+-------------+

执行查询2

mysql> explain  select * from test where addtime='2015-10-13 15:38:32' order by  a , b ,c;
+----+-------------+-------+------+---------------+------+---------+-------+------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+-------+------+-----------------------------+
| 1 | SIMPLE | test | ref | u | u | 8 | const | 4 | Using where; Using filesort |
+----+-------------+-------+------+---------------+------+---------+-------+------+-----------------------------+

使用filesort的情况

a、where语句与order by语句,使用了不同的索引

b、 检查的行数过多,且没有使用覆盖索引

c、对索引列同时使用了ASC和DESC

d、where语句或者ORDER BY语句中索引列使用了表达式,包括函数表达式

e、where 语句与ORDER BY语句组合满足最左前缀,但where语句中使用了条件查询

f、 当使用left join,使用右边的表字段排序

2 利用内存/磁盘文件排序获取结果

由于没有可以利用的有序索引取得有序的数据,MySQL需要通过相应的排序算法,将取得的数据在sort_buffer_size系统变量所设置大小的排序区进行排序,这个排序区是每个Thread 独享的,所以说可能在同一时刻在 MySQL 中可能存在多个 sort buffer 内存区域

MySQL中filesort 的实现算法有两种:

1) 双路排序:<sort_key, rowid> 是首先根据相应的条件取出相应的排序字段和可以直接定位行数据的行指针信息,然后在sort buffer 中进行排序(but this will be essentially hit the table in random order and is not very fast)。
2) 单路排序:是一次性取出满足条件行的所有字段,然后在sort buffer中进行排序。

在 MySQL4.1 版本之前只有第一种排序算法,第二种算法是从MySQL4.1开始的改进算法,主要目的是为了减少第一次算法中需要两次访问表数据的IO操作,将两次变成了一次,但相应也会耗用更多的 sort buffer 空间。典型的以空间换时间的优化方式。当然,MySQL4.1开始的以后所有版本同时也支持第一种算法

MySQL主要通过比较系统参数 max_length_for_sort_data的大小和Query语句所取出的字段类型大小总和来判定需要使用哪一种排序算法。如果max_length_for_sort_data更大,则使用第二种优化后的算法,反之使用第一种算法。所以如果希望 order BY 操作的效率尽可能的高,需要注意max_length_for_sort_data参数的设置。

3、使用Using temporary 临时表来filesort

如果order by的子句只引用了联接中的第一个表,MySQL会先对第一个表进行排序,然后进行联接,expain中的Extra会出现Using Filesort

否则MySQL先把结果保存到临时表(Temporary Table),然后再对临时表的数据进行排序,此时expain中的Extra的显示Using temporary Using Filesort

4、Join排序

mysql中有三种方式

1)、Use index-based access method that produces ordered output  -》 null

2)、Use filesort() on 1st non-constant table -》 “Using filesort” in the first row

3)、Put join result into a temporary table and use filesort() on it   -》  “Using temporary; Using filesort” in the first row


5、说一下filesort,可以参考 What does Using filesort mean in MySQL?

摘自原文

The truth is, filesort is badly named. Anytime a sort can’t be performed from an index, it’s a filesort. It has nothing to do with files. Filesort should be called “sort.” It is quicksort at heart.

If the sort is bigger than the sort buffer, it is performed a bit at a time, and then the chunks are merge-sorted to produce the final sorted output. There is a lot more to it than this. I refer you to Sergey Petrunia’s article on How MySQL executes ORDER BY. You can also read about it in our book, but if you read Sergey’s article you won’t need to.

这里有一个误区,容易望文生义,Explain 命令输出信息中的 filesort 到底是什么意思呢?其实很简单,就是告诉你 MySQL 需要进行实际的排序操作而不能通过索引获得已排序数据

1)、filesort(其实就是排序) 可不一定会产生临时表

2)、filesort 与临时表数据写入磁盘是没有任何直接联系的


二 、优化order by

当无法避免排序操作时,又该如何来优化呢?很显然,优先选择第一种using index 的排序方式,在第一种方式无法满足的情况下,尽可能让 MySQL 选择使用第二种单路算法来进行排序。这样可以减少大量的随机IO操作,很大幅度地提高排序工作的效率。

1、加大 max_length_for_sort_data 参数的设置

在 MySQL 中,决定使用老式排序算法还是改进版排序算法是通过参数 max_length_for_ sort_data 来决定的。当所有返回字段的最大长度小于这个参数值时,MySQL 就会选择改进后的排序算法,反之,则选择老式的算法。所以,如果有充足的内存让MySQL 存放须要返回的非排序字段,就可以加大这个参数的值来让 MySQL 选择使用改进版的排序算法。

2、去掉不必要的返回字段

当内存不是很充裕时,不能简单地通过强行加大上面的参数来强迫 MySQL 去使用改进版的排序算法,否则可能会造成 MySQL 不得不将数据分成很多段,然后进行排序,这样可能会得不偿失。此时就须要去掉不必要的返回字段,让返回结果长度适应 max_length_for_sort_data 参数的限制。

3 增大 sort_buffer_size 参数设置

这个值如果过小的话,再加上你一次返回的条数过多,那么很可能就会分很多次进行排序,然后最后将每次的排序结果再串联起来,这样就会更慢,增大 sort_buffer_size 并不是为了让 MySQL选择改进版的排序算法,而是为了让MySQL尽量减少在排序过程中对须要排序的数据进行分段,因为分段会造成 MySQL 不得不使用临时表来进行交换排序。

但是这个值不是越大越好:

1 Sort_Buffer_Size 是一个connection级参数,在每个connection第一次需要使用这个buffer的时候,一次性分配设置的内存。
2 Sort_Buffer_Size 并不是越大越好,由于是connection级的参数,过大的设置+高并发可能会耗尽系统内存资源。
3 据说Sort_Buffer_Size 超过2M的时候,就会使用mmap() 而不是 malloc() 来进行内存分配,导致效率降低。

参考文章:

https://www.percona.com/blog/2009/03/05/what-does-using-filesort-mean-in-mysql/

http://s.petrunia.net/blog/?p=24

mysql中的order by的更多相关文章

  1. mysql中对order by的函数substring_index() , find_in_set()使用

    题目是这样的:sql = "select  *  from table  where  id  in(3,1,2,5)";  怎样使得查询的结果按照 3 ,1 , 2, 5来排序: ...

  2. mysql中使用order 出现错误

  3. MySQL中怎么对varchar类型排序问题

    MySQL中怎么对varchar类型排序问题 在mysql默认order by 只对数字与日期类型可以排序,但对于varchar字符型类型排序好像没有用了,下面我来给各位同学介绍varchar类型排序 ...

  4. MySQL中怎么对varchar类型排序问题(转)

    在mysql默认order by 只对数字与日期类型可以排序,但对于varchar字符型类型排序好像没有用了,下面我来给各位同学介绍varchar类型排序问题如何解决.   今天在对国家电话号码表进行 ...

  5. mysql中的文件排序(filesort)

    在MySQL中的ORDER BY有两种排序实现方式: 1. 利用有序索引获取有序数据 2. 文件排序 在explain中分析查询的时候,利用有序索引获取有序数据显示Using index ,文件排序显 ...

  6. 转:深入研究mysql中group by与order by取分类最新时间内容

    鉴于项目的需要,就从网上找到该文章,文章分析得很详细也很易懂,在android里, (不知道是不是现在水平的限制,总之我还没找到在用ContentProvider时可以使用子查询),主要方法是用SQL ...

  7. MySQL中order by中关于NULL值的排序问题

    MySQL中order by 排序遇到NULL值的问题 MySQL数据库,在order by排序的时候,如果存在NULL值,那么NULL是最小的,ASC正序排序的话,NULL值是在最前面的. 如果我们 ...

  8. mysql 中order by 与group by的顺序

    mysql 中order by 与group by的顺序 是: select from where group by order by 注意:group by 比order by先执行,order b ...

  9. MySQL中union和order by一起使用的方法

    MySQL中union和order by是可以一起使用的,但是在使用中需要注意一些小问题,下面通过例子来说明.首先看下面的t1表. 1.如果直接用如下sql语句是会报错:Incorrect usage ...

随机推荐

  1. oracle直方图

    直方图 当某列数据分布不均衡.为了让CBO能生成最佳的运行计划,我们可能须要对表收集直方图,直方图最大的桶数(Bucket)是254. 收集直方图是一个很耗时的过程,如无必要.千万别去收集直方图. O ...

  2. 收藏的iOS技术站点汇总(持续更新ing)

    大牛博客 objc.io PS:经典,内容深而广 objc中国 NSHipster PS:非常多小细节 NSHipster 中文版 唐巧的技术博客 PS:LZ是唐巧的脑残粉- OneV's Den 王 ...

  3. 淘宝Tprofiler工具实现分析

    工具介绍TProfiler是一个可以在生产环境长期使用的性能分析工具.它同时支持剖析和采样两种方式,记录方法执行的时间和次数,生成方法热点 对象创建热点 线程状态分析等数据,为查找系统性能瓶颈提供数据 ...

  4. Go 语言简介(上)— 语法

    周末天气不好,只能宅在家里,于是就顺便看了一下Go语言,觉得比较有意思,所以写篇文章介绍一下.我想写一篇你可以在乘坐地铁或公交车上下班时就可以初步了解一门语言的文章.所以,下面的文章主要是以代码和注释 ...

  5. 语义后承(semantic consequence),句法后承(syntactic consequence),实质蕴含(material implication / material conditional)

    作者:罗心澄链接:https://www.zhihu.com/question/21191299/answer/17469774来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...

  6. java.lang.ClassNotFoundException: Didn&#39;t find class &quot;stu.love.neihan.MainActivity&quot; on path: DexPathL

    java.lang.ClassNotFoundException: Didn't find class "stu.love.neihan.MainActivity" on path ...

  7. Linux监听进程是否存在,并加入定时任务

    前言 我们在linux主机上可能需要一直运行某一服务,如果关机后或者误杀,使得服务停止,从而影响日常的任务.比如一BI项目数据库的抽取,使用Taskctl调度,在每天固定时间进行数据的抽取,如果主机上 ...

  8. [Ajax] AJAX初体验之-在博客中添加无刷新搜索

    现在博客很流行,相信应该上网时间稍微长点的朋友都会在这或者在那的有一个自己的博客.对于一些有一定能力的朋友,可能更喜欢自己去下载一个博客程序来架设一个自己的博客,而不是使用一些博客网站提供的服务.而大 ...

  9. 深入理解VUE样式style层次分析

    刚开始使用vue的时候容易被里面的样式搞懵: 样式可以在main.js中引入,在模块js文件中引入,在组件中的style标签引入,在组件中的script标签引入,还可以在index.html的body ...

  10. Android之PowerManager&BatteryManager

    PowerManager是Android平台中用于管理控制设备电源状态.重启.休眠状态.唤醒等,使用该API会影响到电池的待机时间,所以无非必要,一般不要使用. 在PowerManager中有几个比较 ...