mysql order by 排序原理解析

 更新时间:2024年02月09日 09:49:37   作者:曹朋羽  
当涉及到大量数据时,对于 ORDER BY 操作,可以考虑为相应的列添加索引,如果不使用索引,mysql会使用filesort来进行排序,这篇文章主要介绍了mysql order by 排序原理,需要的朋友可以参考下

sql语句按照指定的字段进行排序是查询数据时是一个很常见的操作。当涉及到大量数据时,对于 ORDER BY 操作,可以考虑为相应的列添加索引,如果不使用索引,mysql会使用filesort来进行排序。

filesort

filesort虽然有file,但是不一定是文件排序,要分情况。下面来看下排序的具体逻辑。

filesort会将查询行数据放入sort_buffer中,然后按排序字段进行排序。sort_buffer的大小有变量sort_buffer_size来控制,默认大小256kb。

mysql> SELECT @@sort_buffer_size;
+--------------------+
| @@sort_buffer_size |
+--------------------+
|             262144 |

如果要排序的数据内容小于sort_buffer_size,排序在内存中即可完成;否则filesort会使用临时文件进行排序。数据越多生成的临时文件越多,每份文件单独排序后再归并合并成一个有序的结果。

临时文件存放再 tmpdir 变量指定的目录下,排序完成后会自动删除。

mysql> select @@tmpdir;
+----------+
| @@tmpdir |
+----------+
| /tmp     |

如果使用了filesort,在explain的Extra会显示:Using filesort。是否使用了临时文件还需要根据具体的执行过程来判断。下面通过information_schema.OPTIMIZER_TRACE表来查看是否使用临时文件。

1、准备一个t_user表,首先开启optimizer_trace

mysql> SET optimizer_trace='enabled=on';

2、然后执行查看explain这里再Extra会有Using filesort。

mysql> explain select * from t_user order by username;
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra          |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+----------------+
|  1 | SIMPLE      | t_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 2700 |   100.00 | Using filesort |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+----------------+
1 row in set, 1 warning (0.00 sec)

3、执行查询

select * from t_user order by username;

注意这里是执行查询,不是explain,否则下面一步看不到信息

4、查看OPTIMIZER_TRACE

SELECT * FROM information_schema.OPTIMIZER_TRACE;

OPTIMIZER_TRACE一共有4列:

QUERY:表示当前查询语句

TRACE: 包含查询优化器的trace信息,json格式

MISSING_BYTES_BEYOND_MAXMEM:丢失字节数。

在trace内容中有“filesort_summary”部分是关于filesort处理信息,如上面查询对应的filesort_summary

mysql8:

"filesort_summary": {
  "memory_available": 262144,
  "key_size": 481,
  "row_size": 6591,
  "max_rows_per_buffer": 39,
  "num_rows_estimate": 2700,
  "num_rows_found": 2800,
  "num_initial_chunks_spilled_to_disk": 8,
  "peak_memory_used": 264192,
  "sort_algorithm": "std::sort",
  "sort_mode": "<fixed_sort_key, packed_additional_fields>"
}

mysql5.7:

"filesort_summary": {
  "rows": 2800,
  "examined_rows": 2800,
  "number_of_tmp_files": 6,
  "sort_buffer_size": 261784,
  "sort_mode": "<sort_key, rowid>"
}

这里看到5.7和8差别还是有点大,但是几个主要的字段还是差不多的。这里以5.7的trace信息来看。

sort_buffer_size是sort_buffer的大小。

rows:数据行数

number_of_tmp_files:临时文件数,如果该值为0,则表示未使用临时文件,sort_buffer够用。

sort_mode:排序方式。这个指定了参与排序的数据内容不同。

sort_key, rowid:sort_buffer中加载的数据只有排序字段(sort_key)和rowid,rowid用来排序后再回表查询获取行数据。

sort_key, additional_fields:sort_buffer中加载数据包含所有的要查询的字段。

sort_key, packed_additional_fields:和上面的additional_fields差不多,只是有些可变长度会进行压缩。

那么sort_mode这两种类型一种有所有查询字段,一种只有排序字段,查询优化器是根据什么选择的呢。这里有一个参数max_length_for_sort_data,如果查询的数据行记录超过该值,则会采用sort_key, rowid模式,否则会采用sort_key, additional_fields模式。不过这个值在MySQL 8.0.20被标为过时了,建议通过调整sort_buffer_size大小来控制join_buffer大小,尽量避免使用磁盘临时文件。这两种排序模式比较:additional_fields模式不需要回表,如果查询的列比较多,可能会导致sort_buffer所能容纳的行数据变少;rowid模式每行数据很小,sort_buffer可以加载更多的行,但是最后返回数据要回表。不同数据量场景,要合理设置sort_buffer_size和max_length_for_sort_data搭配。

这里看到排序的过程,一行行拿出来进行比较,数据量大还会使用到临时文件,还是比较耗时的。那么有没有更快的方法呢?那就是使用索引。

使用索引

为什么使用索引会快?因为构建后的索引就是天然有序的,不需要再经过一行行逐一对sort_key进行比较。跳过额外的filesort。

排序使用索引的情况一般在Extra中只有Using index。使用索引一般场景:

1、查询条件中有排序索引

2、索引覆盖,查询的列都在对应的索引中

3、多列索引排序,满足最左匹配

4、排序方向一致

这只是一般的规则,下面结合几个具体的例子来看看。

t_user表上有复合索引 (username,gender,department) 还有索引(phone)

例1:

SELECT uid,phone FROM t_user ORDER BY phone;

查询列都在索引上(uid是主键),Using index

例2:

SELECT * FROM t_user ORDER BY phone;

索引不包含查询访问的所有列,则仅当索引访问比其他访问方法更高效时才使用该索引.这里查询优化器选择了Using filesort。 不太理解?

例3:

SELECT uid,phone FROM t_user WHERE uid<20 ORDER BY phone;

虽然查询内容是索引覆盖,但是where条件不在索引上(不是同一个索引),Using filesort。

这个应该可以理解一个索引筛选出来的数据内容对另一个索引是无序的。

例4:

SELECT username,gender FROM t_user  ORDER BY username,gender;
SELECT username,gender FROM t_user WHERE username='a' ORDER BY gender;

查询内容索引覆盖,where满足索引最左匹配部分,Using index。

例5:

SELECT username,gender FROM t_user WHERE username LIKE 'a%'  ORDER BY username desc,gender ;

多列排序,第一列排序username满足使用索引条件,gender和username排序方向相反,无法使用索引,会进行依次filesort。

例6:

SELECT username,gender FROM t_user WHERE username LIKE 'a%'  ORDER BY username,department ;

username排序使用filesort,department排序不满足最左匹配,中间复合索引断开(缺少gender)使用filesort。

这里只看了几个常见例子,可能有些场景比这复杂的多。想一想能使用到索引排序一个最基本的条件:当前要查询的数据范围(where筛选后)在排序列(对应的索引)是有序的。然后才考虑覆盖索引等其它需要满足的条件。

到此这篇关于mysql order by 排序原理的文章就介绍到这了,更多相关mysql order by 排序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一次MySQL慢查询导致的故障

    一次MySQL慢查询导致的故障

    这篇文章主要介绍了如何对MySQL慢查询导致的故障进行处理,慢查询是我们在mysql中经常需要使用到的一个很方便的功能,慢查询对于跟踪有问题的查询很有用,需要的朋友可以参考下
    2015-08-08
  • winxp 安装MYSQL 出现Error 1045 access denied 的解决方法

    winxp 安装MYSQL 出现Error 1045 access denied 的解决方法

    自己遇到了这个问题,也找了很久才解决,就整理一下,希望对大家有帮助!
    2010-07-07
  • MySQL主从同步机制与同步延时问题追查过程

    MySQL主从同步机制与同步延时问题追查过程

    这篇文章主要给大家介绍了关于MySQL主从同步机制与同步延时问题追查的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-02-02
  • MySQL数据库之联合查询 union

    MySQL数据库之联合查询 union

    这篇文章主要介绍了MySQL数据库之联合查询 union,联合查询就是将多个查询结果的结果集合并到一起,字段数不变,多个查询结果的记录数合并,下文详细介绍需要的小伙伴可以参考一下
    2022-06-06
  • mysql表格id清零的三种方法

    mysql表格id清零的三种方法

    本文主要介绍了mysql表格id清零的三种方法,主要包括TRUNCATE TABLE语句,ALTER TABLE语句和DELETE语句,具有一定的参考价值,感兴趣的可以了解一下
    2023-11-11
  • mysql正则函数REGEXP使用及说明

    mysql正则函数REGEXP使用及说明

    本文介绍了MySQL中的正则表达式匹配操作符REGEXP及其在不同版本中的使用方法和差异,包括基本语法、支持的元字符与量词、版本差异及常用函数如REGEXP_LIKE、REGEXP_SUBSTR、REGEXP_REPLACE等
    2026-05-05
  • 宝塔面板mysql无法启动问题的分析和解决

    宝塔面板mysql无法启动问题的分析和解决

    在使用宝塔linux面板一键安装LNMP的是,数据库mysql始终无法启动,查查找找用了几个小时,问题终于解决了,下面这篇文章主要给大家介绍了关于宝塔面板mysql无法启动问题的分析和解决方法,需要的朋友可以参考下
    2023-04-04
  • MySQL ClickHouse常用表引擎超详细讲解

    MySQL ClickHouse常用表引擎超详细讲解

    这篇文章主要介绍了MySQL ClickHouse常用表引擎,ClickHouse表引擎中,CollapsingMergeTree和VersionedCollapsingMergeTree都能通过标记位按规则折叠数据,从而达到更新和删除的效果
    2022-11-11
  • MySql与Navicat安装教程分享

    MySql与Navicat安装教程分享

    这篇文章主要介绍了MySql与Navicat安装教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • Mysql使用on update current_timestamp问题

    Mysql使用on update current_timestamp问题

    这篇文章主要介绍了Mysql使用on update current_timestamp问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03

最新评论