MySQL的ORDER BY优化

除了常规的Join语句之外,还有一类Query语句也是使用比较频繁的,那就是ORDER BY,GROUP BY以及DISTINCT这三类查询。考虑到这三类查询都涉及到数据的排序等操作,所以我将他们放在了一起,下面就针对这三类Query语句做基本的分析。

一、ORDER BY的实现与优化

1、在MySQL中,ORDER BY的实现有如下两种类型:
◆ 一种是通过有序索引而直接取得有序的数据,这样不用进行任何排序操作即可得到满足客户端要求的有序数据返回给客户端;
◆ 另外一种则需要通过MySQL的排序算法将存储引擎中返回的数据进行排序然后再将排序后的数据返回给客户端。

2、第一种情况:
这种利用索引实现数据排序的方法是MySQL中实现结果集排序的最佳做法,可以完全避免因为排序计算所带来的资源消耗。所以,在我们优化Query语句中的ORDER BY的时候,尽可能利用已有的索引来避免实际的排序计算,可以很大幅度的提升ORDER BY操作的性能。

在有些Query的优化过程中,即使为了避免实际的排序操作而调整索引字段的顺序,甚至是增加索引字段也是值得的。当然,在调整索引之前,同时还需要评估调整该索引对其他Query所带来的影响,平衡整体得失。

3、第二种情况:
必须进行相应的排序算法来实现数据的排序。MySQL目前可以通过两种算法来实现数据的排序操作。

1)取出满足过滤条件的用于排序条件的字段以及可以直接定位到行数据的行指针信息,在Sort Buffer中进行实际的排序操作,然后利用排好序之后的数据根据行指针信息返回表中取得客户端请求的其他字段的数据,再返回给客户端;

2)根据过滤条件一次取出排序字段以及客户端请求的所有其他字段的数据,并将不需要排序的字段存放在一块内存区域中,然后在Sort Buffer中将排序字段和行指针信息进行排序,最后再利用排序后的行指针与存放在内存区域中和其他字段一起的行指针信息进行匹配合并结果集,再按照顺序返回给客户端。

在我们实际应用中,可能需要排序的字段同时存在于两个表中,或者MySQL在经过一次Join之后才进行排序操作。这样的排序在MySQL中并不能简单的里利用Sort Buffer进行排序,而是必须先通过一个临时表将之前Join的结果集存放入临时表之后在将临时表的数据取到Sort Buffer中进行操作。

要看排序是在表join之前还是之后。

4、如何优化
当我们无法避免排序操作的时候,我们又该如何来优化呢?很显然,我们应该尽可能让MySQL选择使用第二种算法来进行排序。这样可以减少大量的随机IO操作,很大幅度的提高排序工作的效率。

1)加大max_length_for_sort_data参数的设置
在MySQL中,决定使用第一种老式的排序算法还是新的改进算法的依据是通过参数max_length_for_sort_data来决定的。当我们所有返回字段的最大长度小于这个参数值的时候,MySQL就会选择改进后的排序算法,反之,则选择老式的算法。

2)去掉不必要的返回字段
当我们的内存并不是很充裕的时候,我们就需要去掉不必要的返回字段,让我们的返回结果长度适应max_length_for_sort_data参数的限制。

3)增大sort_buffer_size参数设置
增大sort_buffer_size并不是为了让MySQL可以选择改进版的排序算法,而是为了让MySQL可以尽量减少在排序过程中对需要排序的数据进行分段,因为这样会造成MySQL不得不使用临时表来进行交换排序。