千家信息网

(转)MySQL ORDER BY 的实现分析

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,作者:Sky.Jian | 可以任意转载, 但转载时务必以超链接形式标明文章原始出处 和 作者信息 及 版权声明链接:http://www.jianzhaoyang.com/database/mysq
千家信息网最后更新 2026年11月01日(转)MySQL ORDER BY 的实现分析作者:Sky.Jian | 可以任意转载, 但转载时务必以超链接形式标明文章原始出处 和 作者信息 及 版权声明
链接:http://www.jianzhaoyang.com/database/mysql_order_by_implement

总的来说,在 MySQL 中的ORDER BY有两种排序实现方式,一种是利用有序索引获取有序数据,另一种则是通过相应的排序算法,将取得的数据在内存中进行排序。

下面将通过实例分析两种排序实现方式及实现图解:
假设有 Table A 和 B 两个表结构分别如下:

[@more@]sky@localhost : example01:48:21; showcreatetableAG
***************************
1.row **************************Table: ACreateTable: CREATETABLE`A`(`c1`int(11)NOTNULLdefault'0',`c2`char(2)defaultNULL,`c3`varchar(16)defaultNULL,`c4`datetimedefaultNULL,PRIMARYKEY (`c1`))ENGINE=MyISAMDEFAULTCHARSET=utf8
sky@localhost : example01:48:32; showcreatetableBG
***************************
1.row***************************Table: BCreateTable: CREATETABLE`B`(`c1`int(11)NOTNULLdefault'0',`c2`char(2)defaultNULL,`c3`varchar(16)defaultNULL,PRIMARYKEY (`c1`),KEY`B_c2_ind`(`c2`))ENGINE=MyISAMDEFAULTCHARSET=utf8

1、利用有序索引进行排序,实际上就是当我们 Query 的 ORDER BY 条件和 Query 的执行计划中所利用的 Index 的索引键(或前面几个索引键)完全一致,且索引访问方式为 rang、 ref 或者 index 的时候,MySQL 可以利用索引顺序而直接取得已经排好序的数据。这种方式的 ORDER BY 基本上可以说是最优的排序方式了,因为 MySQL 不需要进行实际的排序操作。

假设我们在Table A 和 B 上执行如下SQL:

sky@localhost : example01:44:28; EXPLAINSELECTA.* FROMA,BWHEREA.c12ANDA.c25ANDA.c2 = B.c2ORDERBYA.c1G
***************************
1.row**************************id: 1select_type: SIMPLEtable: Atype: rangepossible_keys: PRIMARYkey: PRIMARYkey_len: 4ref: NULLrows: 3Extra: Usingwhere
***************************
2.row***************************id: 1select_type: SIMPLEtable: Btype: refpossible_keys: B_c2_indkey: B_c2_indkey_len: 7ref: example.A.c2rows: 2Extra: Usingwhere; Usingindex

我们通过执行计划可以看出,MySQL实际上并没有进行实际的排序操作,实际上其整个执行过程如下图所示:

2、通过相应的排序算法,将取得的数据在内存中进行排序方式,MySQL 比需要将数据在内存中进行排序,所使用的内存区域也就是我们通过 sort_buffer_size 系统变量所设置的排序区。这个排序区是每个 Thread 独享的,所以说可能在同一时刻在 MySQL 中可能存在多个 sort buffer 内存区域。

第二种方式在 MySQL Query Optimizer 所给出的执行计划(通过 EXPLAIN 命令查看)中被称为 filesort。在这种方式中,主要是由于没有可以利用的有序索引取得有序的数据,MySQL只能通过将取得的数据在内存中进行排序然后再将数据返回给 客户端。在 MySQL 中 filesort 的实现算法实际上是有两种的,一种是首先根据相应的条件取出相应的排序字段和可以直接定位行数据的行指针信息,然后在 sort buffer 中进行排序。另外一种是一次性取出满足条件行的所有字段,然后在 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 参数的设置。曾经就有同事的数据库出现大量的排序等待,造成系统负载很高,而且响应时间变得很长,最后查出正是因为 MySQL 使用了传统的第一种排序算法而导致,在加大了 max_length_for_sort_data 参数值之后,系统负载马上得到了大的缓解,响应也快了很多。

我们再看看 MySQL 需要使用 filesort 实现排序的实例。

假设我们改变一下我们的 Query,换成通过A.c2来排序,再看看情况:

sky@localhost : example01:54:23; EXPLAINSELECTA.* FROMA,BWHEREA.c12ANDA.c25ANDA.c2 = B.c2ORDERBYA.c2G
***************************
1.row***************************id: 1select_type: SIMPLEtable: Atype: rangepossible_keys: PRIMARYkey: PRIMARYkey_len: 4ref: NULLrows: 3Extra: Usingwhere; Usingfilesort
***************************
2.row***************************id: 1select_type: SIMPLEtable: Btype: refpossible_keys: B_c2_indkey: B_c2_indkey_len: 7ref: example.A.c2rows: 2Extra: Usingwhere; Usingindex

MySQL 从 Table A 中取出了符合条件的数据,由于取得的数据并不满足 ORDER BY 条件,所以 MySQL 进行了 filesort 操作,其整个执行过程如下图所示:

在 MySQL 中,filesort 操作还有一个比较奇怪的限制,那就是其数据源必须是来源于一个 Table,所以,如果我们的排序数据如果是两个(或者更多个) Table 通过 Join所得出的,那么 MySQL 必须通过先创建一个临时表(Temporary Table),然后再将此临时表的数据进行排序,如下例所示:

sky@localhost : example02:46:15; explainselectA.* fromA,BwhereA.c12andA.c25andA.c2 = B.c2orderbyB.c3G
***************************
1.row***************************id: 1select_type: SIMPLEtable: Atype: rangepossible_keys: PRIMARYkey: PRIMARYkey_len: 4ref: NULLrows: 3Extra: Usingwhere; Usingtemporary; Usingfilesort
***************************
2.row***************************id: 1select_type: SIMPLEtable: Btype: refpossible_keys: B_c2_indkey: B_c2_indkey_len: 7ref: example.A.c2rows: 2Extra: Usingwhere

这个执行计划的输出还是有点奇怪的,不知道为什么,MySQL Query Optimizer 将 "Using temporary" 过程显示在第一行对 Table A 的操作中,难道只是为让执行计划的输出少一行?

实际执行过程应该是如下图所示:

排序 数据 算法 方式 实际 索引 内存 有序 条件 实际上 系统 过程 参数 字段 一行 两个 作者 信息 区域 大小 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 南京欣网互联网络科技有限公司 互联网金融 科技金融 互联网 科技创新 互联网科技公司怎么样 世界互联网领先科技成果 碳银互联网科技有限公司 互联网科技公司有哪些 长亮科技 互联网金融 深圳卡尔迅互联网科技有限公司怎么样 昭通云南众福互联网科技有限公司 互联网大会黑科技排名 宁夏众和广鑫互联网科技有限公司 宁夏科技产业互联网案例 电子科技大学互联网创业大赛 佛山市拉法互联网科技有限公司 长沙茂晟互联网科技有限公司 合肥互联网科技公司公章图片 抖集互联网科技技术咨询 互联网科技博主张洲 银川新华互联网科技学校招聘 科技互联网项目 金融科技和互联网金融 移动互联网年度科技创新 亳州好赞互联网科技有限公司 燊美集互联网科技有限公司 深圳艾果互联网通讯科技 朱啸虎曾投资哪些互联网科技企业 2021世界互联网领先科技成果发布 互联网时代科技型公司的机会 北京品多多互联网科技有限公司
0