关于 order By 函数,你可以知道更多


一个非常类似的问题,可以看这里:

这句简单的sql,如何加索引?颠覆了我多年的认知

。这篇可以算是扩展阅读,希望对你有所帮助。

order by 是我们常用的 SQL 函数之一,如果我们需要返回结果集为有序的,则我们需要使用 order by 函数。

假设我们现在有一个需求,查询用户表中来自江西的用户,并且按照名字排序返回前 20 位,面对这种需求我们就需要利用 order by 函数来帮我们实现。

用户表定义如下:

<code>CREATE TABLE `user` (
`id` int(11) NOT NULL,
`city` varchar(16) NOT NULL,
`name` varchar(16) NOT NULL,
`age` int(11) NOT NULL,
`addr` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `city` (`city`)
) ENGINE=InnoDB;
/<code>

我们的 SQL 语句就可以这样写:

<code>select city,name,age from user where city='江西' order by name limit 20;
/<code>

这样返回来的数据就是有序的,order by 函数背后是如何运行的?帮助我们完成结果集排序。

order by 函数要满足结果集排序要求,在 MySQL 数据库中,有两种方式来实现:

利用索引满足和使用文件排序

使用文件排序

先使用 explain 查看上述语句的执行情况

可以看到 Extra 这一行,显示为 Using filesort,说明使用了文件排序。对于文件排序 MySQL 数据库会给每个线程分配一块排序内存(sort_buffer)。sort_buffer 的大小可以通过 sort_buffer_size 来控制,默认值为 262144。

在文件排序中根据 max_length_for_sort_data 情况,MySQL 提供了两种算法,如果我们返回的字段长度总和小于 max_length_for_sort_data 的值,这会将所有的字段都放入到 sort_buffer 中,我们称之为全字段排序

如果返回的字段长度总和大于 max_length_for_sort_data 设置的值,则只会将 id,排序字段放入到 sort_buffer 中,最后排序后再回主键索引中查询所有数据,这种称之为 rowid 排序

全字段排序和 rowid排序 的区别在于数据在 sort_buffer 排序内存中排序后,全字段排序算法在sort_buffer 的临时表中已经有所有的返回字段,不需要再回主键索引中查询信息,可以直接返回给用户,而 rowid排序算法在sort_buffer 中只有部分字段,需要再回主键索引中查询数据,才能返回给用户。

可能看了还是有点懵逼,可以参考下面这张图,加深理解:

文件排序优先在 sort_buffer 内存块中完成,如果需要排序的数据量大于 sort_buffer_size 的值,那么就需要借助磁盘临时文件来完成排序,那么性能就回有所下降,所以在内存允许的情况下,可以适当的增大 sort_buffer_size 的值,来减少使用磁盘文件排序的机率

对于全字段排序和rowid排序,优选选择使用全字段排序,因为rowid排序需要回表查询,会造成磁盘读,不会被 MySQL 优选使用。在 MySQL8 中好像已经取消了。

利用索引排序

我们还可以利用联合索引来满足排序要求,因为索引在存储的时候就是有序的,所以在读取的时候自然就有序了。

对于这条 SQL 语句:

<code>select city,name,age from user where city='江西' order by name limit 20;
/<code>

我们可以创建一个city、name、age的联合索引,添加索引的SQL 语句为:

<code>alter table t add index city_user_age(city, name, age);
/<code>

再次使用 explain 查看 SQL 语句执行过程:

图片描述

还是看 Extra 这一行,不再是 Using filesort,而是 Using index了,说明使用联合索引。

此时这条语句的执行流程大概如下:

1、从索引 (city,name,age) 找到第一个满足 city='江西’条件的记录,取出其中的 city、name 和 age 这三个字段的值,作为结果集的一部分直接返回;2、从索引 (city,name,age) 取下一个记录,同样取出这三个字段的值,作为结果集的一部分直接返回;3、重复执行步骤 2,直到查到第 1000 条记录,或者是不满足 city='江西’条件时循环结束。

图片来源极客时间


使用索引来满足排序性能要好不少,但是维护索引需要不少的代价,任何一种技术没有最好,只有最合适。


文章来源于互联网平头哥 ,作者互联网平头哥