MySQL ORDER BY 性能优化详解:Using filesort、联合索引、ASC/DESC 与覆盖索引
- [MySQL ORDER BY 性能优化详解:Using filesort、联合索引、ASC/DESC 与覆盖索引](#MySQL ORDER BY 性能优化详解:Using filesort、联合索引、ASC/DESC 与覆盖索引)
- [一、先说结论:ORDER BY 应该怎么优化?](#一、先说结论:ORDER BY 应该怎么优化?)
- [二、MySQL ORDER BY 为什么会慢?](#二、MySQL ORDER BY 为什么会慢?)
- [三、什么是 Using filesort?](#三、什么是 Using filesort?)
-
- [Using filesort 是不是一定会使用磁盘?](#Using filesort 是不是一定会使用磁盘?)
- [四、如何避免 Using filesort?](#四、如何避免 Using filesort?)
- [五、案例:没有索引时的 ORDER BY](#五、案例:没有索引时的 ORDER BY)
- [六、建立 age + phone 联合索引](#六、建立 age + phone 联合索引)
- [七、为什么 ORDER BY age 可以使用 age, phone 联合索引?](#七、为什么 ORDER BY age 可以使用 age, phone 联合索引?)
- [八、多字段 ORDER BY 也要注意联合索引顺序](#八、多字段 ORDER BY 也要注意联合索引顺序)
- [九、为什么 ORDER BY phone, age 不能直接使用 (age, phone) 排序?](#九、为什么 ORDER BY phone, age 不能直接使用 (age, phone) 排序?)
- [十、ORDER BY 与联合索引的最左原则](#十、ORDER BY 与联合索引的最左原则)
- [十一、两个字段全部 DESC,还能使用 ASC 索引吗?](#十一、两个字段全部 DESC,还能使用 ASC 索引吗?)
- [十二、为什么 ASC + DESC 混合排序可能出现 filesort?](#十二、为什么 ASC + DESC 混合排序可能出现 filesort?)
- [十三、如何优化 ASC + DESC 混合排序?](#十三、如何优化 ASC + DESC 混合排序?)
- [十四、四种 ORDER BY 与索引的关系](#十四、四种 ORDER BY 与索引的关系)
- [十五、一个非常重要的技术辨析:Using index ≠ ORDER BY 一定走索引排序](#十五、一个非常重要的技术辨析:Using index ≠ ORDER BY 一定走索引排序)
-
- [1. Using index 的准确含义](#1. Using index 的准确含义)
- [2. 判断 ORDER BY 是否额外排序,看什么?](#2. 判断 ORDER BY 是否额外排序,看什么?)
-
- [没有 Using filesort](#没有 Using filesort)
- [出现 Using filesort](#出现 Using filesort)
- [十六、为什么 ORDER BY 优化建议尽量使用覆盖索引?](#十六、为什么 ORDER BY 优化建议尽量使用覆盖索引?)
- [十七、ORDER BY 索引优化思维图](#十七、ORDER BY 索引优化思维图)
- [十八、如果 Using filesort 无法避免怎么办?](#十八、如果 Using filesort 无法避免怎么办?)
- [十九、sort_buffer_size 是什么?](#十九、sort_buffer_size 是什么?)
- [二十、sort_buffer_size 是不是越大越好?](#二十、sort_buffer_size 是不是越大越好?)
- 二十一、完整案例总结
-
- [场景 1:没有索引](#场景 1:没有索引)
- [场景 2:建立联合索引](#场景 2:建立联合索引)
- [场景 3:全部降序](#场景 3:全部降序)
- [场景 4:调换字段顺序](#场景 4:调换字段顺序)
- [场景 5:一升一降](#场景 5:一升一降)
- [场景 6:建立混合方向索引](#场景 6:建立混合方向索引)
- [二十二、ORDER BY 性能优化的正确排查步骤](#二十二、ORDER BY 性能优化的正确排查步骤)
-
- [第一步:使用 EXPLAIN](#第一步:使用 EXPLAIN)
- 第二步:检查排序字段
- 第三步:检查联合索引字段顺序
- [第四步:检查 ASC / DESC](#第四步:检查 ASC / DESC)
- 第五步:检查能否使用覆盖索引
- [第六步:最后再考虑 sort_buffer_size](#第六步:最后再考虑 sort_buffer_size)
- [二十三、ORDER BY 优化的 4 条核心原则](#二十三、ORDER BY 优化的 4 条核心原则)
-
- [1. 根据排序字段建立合适索引](#1. 根据排序字段建立合适索引)
- [2. 多字段排序注意索引字段顺序](#2. 多字段排序注意索引字段顺序)
- [3. 尽量使用覆盖索引](#3. 尽量使用覆盖索引)
- [4. ASC / DESC 混合时注意索引方向](#4. ASC / DESC 混合时注意索引方向)
- [二十四、FAQ:MySQL ORDER BY 常见问题](#二十四、FAQ:MySQL ORDER BY 常见问题)
-
- [1. MySQL ORDER BY 如何优化?](#1. MySQL ORDER BY 如何优化?)
- [2. Using filesort 是什么意思?](#2. Using filesort 是什么意思?)
- [3. Using filesort 一定很慢吗?](#3. Using filesort 一定很慢吗?)
- [4. Using index 是什么意思?](#4. Using index 是什么意思?)
- [5. Using index; Using filesort 能同时出现吗?](#5. Using index; Using filesort 能同时出现吗?)
- [6. ORDER BY age DESC, phone DESC 能走 (age, phone) 索引吗?](#6. ORDER BY age DESC, phone DESC 能走 (age, phone) 索引吗?)
- [7. 为什么 ORDER BY age ASC, phone DESC 可能不能使用普通联合索引排序?](#7. 为什么 ORDER BY age ASC, phone DESC 可能不能使用普通联合索引排序?)
- [8. ORDER BY phone, age 能使用 (age, phone) 索引吗?](#8. ORDER BY phone, age 能使用 (age, phone) 索引吗?)
- [9. sort_buffer_size 越大越好吗?](#9. sort_buffer_size 越大越好吗?)
- [二十五、一张表总结 MySQL ORDER BY 优化](#二十五、一张表总结 MySQL ORDER BY 优化)
- [二十六、30 秒记住 ORDER BY 优化](#二十六、30 秒记住 ORDER BY 优化)
- 二十七、总结
MySQL ORDER BY 性能优化详解:Using filesort、联合索引、ASC/DESC 与覆盖索引
前言
在 MySQL 中,ORDER BY 是非常常见的排序操作。
例如:
sql
SELECT id, age, phone
FROM tb_user
ORDER BY age, phone;
SQL 本身很简单,但当数据量越来越大时,排序可能成为查询性能瓶颈。
MySQL 对 ORDER BY 的处理,大体可以分为两类:
- 利用索引本身的有序性返回结果
- 无法利用索引顺序,需要额外执行 filesort 排序
因此,优化 ORDER BY 的核心目标可以概括为一句话:
尽可能让 MySQL 利用索引本身的顺序完成排序,减少额外的 filesort。
本文围绕 MySQL ORDER BY 优化展开,重点讲清楚:
Using filesort到底是什么意思Using index又是什么意思- 为什么联合索引可以优化排序
- 为什么
ORDER BY age, phone可以走索引,而ORDER BY phone, age可能不行 - 为什么两个字段同时倒序仍然可以利用索引
- 为什么一升一降可能再次出现
Using filesort - 如何创建
ASC / DESC混合索引 - 覆盖索引为什么有利于排序性能
- 无法避免 filesort 时还能怎么优化
一、先说结论:ORDER BY 应该怎么优化?
如果只记本文最重要的内容,可以记住下面 4 条:
MySQL ORDER BY 优化原则:
- 根据排序字段建立合适的索引;
- 多字段排序时,注意联合索引的字段顺序;
ASC、DESC混合排序时,让索引方向与查询排序方向匹配;- 无法避免
filesort时,再考虑sort_buffer_size等排序参数。
另外,查询字段能够被索引覆盖时,通常还可以减少回表,因此实际优化中也应尽量考虑覆盖索引。
二、MySQL ORDER BY 为什么会慢?
假设执行:
sql
SELECT id, age, phone
FROM tb_user
ORDER BY age, phone;
如果 age、phone 没有合适的索引,MySQL 无法直接按照索引顺序获得最终结果。
此时就需要:
text
读取符合条件的数据
↓
放入排序过程
↓
按照 age、phone 排序
↓
返回最终结果
这会产生额外的排序成本。
在 EXPLAIN 执行计划中,通常可以通过:
text
Using filesort
判断 MySQL 是否额外执行了排序。
三、什么是 Using filesort?
例如执行:
sql
EXPLAIN
SELECT id, age, phone
FROM tb_user
ORDER BY age, phone;
如果当前没有适合排序的索引,Extra 中可能出现:
text
Using filesort
Using filesort 表示 MySQL 不能直接利用索引顺序得到最终排序结果,需要额外执行一次排序阶段 。MySQL 官方文档同样将 filesort 描述为无法通过索引满足 ORDER BY 时执行的额外排序过程。 (MySQL开发者专区)
Using filesort 是不是一定会使用磁盘?
不是。
这是一个很容易产生误解的地方。
虽然名字叫:
text
filesort
但它并不意味着:
"只要出现 Using filesort,就一定会进行磁盘文件排序。"
MySQL 会使用排序缓冲区处理排序;当排序数据无法完全放入内存时,才可能使用临时磁盘文件。 (MySQL开发者专区)
因此更准确的理解是:
filesort 代表额外排序算法,而不是"必然磁盘排序"。
四、如何避免 Using filesort?
关键在于:
利用 B+Tree 索引本身已经有序的特点。
例如我们经常按照:
sql
ORDER BY age, phone
进行排序,那么可以考虑建立联合索引:
sql
CREATE INDEX idx_user_age_phone
ON tb_user(age, phone);
索引本身会按照:
text
age
↓
相同 age 下继续按照 phone
维护有序结构。
于是查询:
sql
SELECT id, age, phone
FROM tb_user
ORDER BY age, phone;
就有机会直接按照索引顺序扫描,而不需要重新对结果进行额外排序。
五、案例:没有索引时的 ORDER BY
首先假设:
text
age
phone
都没有适合当前排序的索引。
执行:
sql
EXPLAIN
SELECT id, age, phone
FROM tb_user
ORDER BY age;
或者:
sql
EXPLAIN
SELECT id, age, phone
FROM tb_user
ORDER BY age, phone;
此时通常可能看到:
text
Using filesort
因为 MySQL 无法借助适合的索引顺序直接返回结果。
六、建立 age + phone 联合索引
创建联合索引:
sql
CREATE INDEX idx_user_age_phone_aa
ON tb_user(age, phone);
没有显式指定方向时,可以理解为:
sql
age ASC,
phone ASC
即:
text
(age ASC, phone ASC)
然后再次执行:
sql
EXPLAIN
SELECT id, age, phone
FROM tb_user
ORDER BY age, phone;
此时 MySQL 就具备了利用索引顺序完成排序的条件。
七、为什么 ORDER BY age 可以使用 age, phone 联合索引?
假设索引为:
text
(age, phone)
那么 B+Tree 首先按照 age 排序,在相同 age 下再按照 phone 排序。
可以抽象成:
text
age
│
├── 18
│ ├── phone A
│ ├── phone B
│ └── phone C
│
├── 20
│ ├── phone A
│ ├── phone B
│ └── phone C
│
└── 25
├── phone A
├── phone B
└── phone C
因此:
sql
ORDER BY age
可以利用索引前半部分的顺序。
同样:
sql
ORDER BY age, phone
也与索引整体顺序匹配。
八、多字段 ORDER BY 也要注意联合索引顺序
现在索引是:
text
(age, phone)
查询:
sql
SELECT id, age, phone
FROM tb_user
ORDER BY age, phone;
排序字段顺序与索引一致:
text
索引:
age → phone
ORDER BY:
age → phone
这种情况可以很好地利用索引。
但是,如果改成:
sql
SELECT id, age, phone
FROM tb_user
ORDER BY phone, age;
排序顺序变成:
text
phone → age
而索引是:
text
age → phone
两者的全局顺序并不一致。
因此很可能再次出现:
text
Using filesort
九、为什么 ORDER BY phone, age 不能直接使用 (age, phone) 排序?
这是理解联合索引排序优化的关键。
对于:
text
INDEX(age, phone)
索引真正保证的是:
text
先按照 age 排序
age 相同时再按照 phone 排序
它并不能保证:
text
所有 phone 在整个索引范围内都是全局有序的
举个例子:
text
age = 18, phone = 135...
age = 18, phone = 139...
age = 20, phone = 131...
age = 20, phone = 138...
按照整个索引看,它首先满足:
text
age 有序
而不是:
text
phone 有序
因此:
sql
ORDER BY phone, age
无法简单通过:
text
(age, phone)
这个索引获得全局正确的排序结果。
十、ORDER BY 与联合索引的最左原则
对于联合索引:
text
(age, phone)
以下查询比较容易利用索引顺序:
sql
ORDER BY age;
以及:
sql
ORDER BY age, phone;
而:
sql
ORDER BY phone;
或者:
sql
ORDER BY phone, age;
通常无法直接使用该联合索引满足完整的排序顺序。
因此可以总结为:
多字段 ORDER BY 优化时,应让排序字段顺序尽可能与联合索引字段顺序匹配。
十一、两个字段全部 DESC,还能使用 ASC 索引吗?
这是本节非常重要的一点。
假设索引:
sql
CREATE INDEX idx_user_age_phone_aa
ON tb_user(age, phone);
其方向可以理解为:
text
age ASC
phone ASC
现在执行:
sql
EXPLAIN
SELECT id, age, phone
FROM tb_user
ORDER BY age DESC, phone DESC;
这种情况下,MySQL 可以通过反向扫描索引获得:
text
age DESC
phone DESC
的结果。
MySQL 8.0 官方文档也明确说明,同方向多列排序时,可以通过对应索引或反向扫描索引满足 ORDER BY。 (MySQL开发者专区)
执行计划中可能看到类似:
text
Backward index scan
表示正在反向扫描索引。
十二、为什么 ASC + DESC 混合排序可能出现 filesort?
现在索引依然是:
text
(age ASC, phone ASC)
执行:
sql
EXPLAIN
SELECT id, age, phone
FROM tb_user
ORDER BY age ASC, phone DESC;
排序要求变成:
text
age ASC
phone DESC
而原来的索引方向是:
text
age ASC
phone ASC
如果直接正向扫描:
text
age ASC √
phone ASC ×
如果整体反向扫描:
text
age DESC ×
phone DESC √
无论正向还是反向扫描,都无法同时满足:
text
age ASC
phone DESC
因此就可能产生:
text
Using filesort
十三、如何优化 ASC + DESC 混合排序?
如果业务中大量出现:
sql
ORDER BY age ASC, phone DESC
可以建立与查询排序方向一致的联合索引:
sql
CREATE INDEX idx_user_age_phone_ad
ON tb_user(age ASC, phone DESC);
此时索引的组织顺序就是:
text
age ASC
phone DESC
再次执行:
sql
EXPLAIN
SELECT id, age, phone
FROM tb_user
ORDER BY age ASC, phone DESC;
MySQL 就具备通过索引顺序直接完成排序的条件。
MySQL 8.0 已经支持真正的降序索引,因此混合 ASC/DESC 的多列排序可以通过匹配方向的联合索引优化。 (MySQL开发者专区)
十四、四种 ORDER BY 与索引的关系
假设存在索引:
text
(age ASC, phone ASC)
可以快速总结成下面这张表:
| ORDER BY | 是否容易利用该索引完成排序 | 原因 |
|---|---|---|
age ASC, phone ASC |
是 | 与索引方向一致 |
age DESC, phone DESC |
是 | 可以反向扫描 |
age ASC, phone DESC |
否 | 两列方向不一致 |
age DESC, phone ASC |
否 | 两列方向不一致 |
如果建立:
text
(age ASC, phone DESC)
那么:
sql
ORDER BY age ASC, phone DESC
就可以利用匹配的索引顺序。
十五、一个非常重要的技术辨析:Using index ≠ ORDER BY 一定走索引排序
很多教程会把:
text
Using index
和:
text
Using filesort
简单理解成:
text
Using index = 性能好
Using filesort = 性能差
作为入门记忆方法没有问题,但严格来说还需要进一步区分。
1. Using index 的准确含义
EXPLAIN Extra 中的:
text
Using index
主要表示:
查询需要的列可以直接从索引中获得,不需要再读取完整的数据行。
也就是我们常说的:
覆盖索引(Covering Index)
2. 判断 ORDER BY 是否额外排序,看什么?
真正判断 ORDER BY 是否进行了额外排序,更重要的是观察:
text
Using filesort
没有 Using filesort
意味着:
text
没有额外执行 filesort 排序
出现 Using filesort
意味着:
text
执行了额外排序阶段
MySQL 官方 EXPLAIN 文档也分别定义了 Using index 和 Using filesort:前者指利用索引树取得查询所需列,后者则表示需要额外排序。 (MySQL开发者专区)
因此可能出现:
text
Using index; Using filesort
这并不矛盾。
它表示:
text
Using index
↓
查询列可以由覆盖索引取得
Using filesort
↓
但是 ORDER BY 仍然需要额外排序
这个区别在分析真实生产 SQL 时非常重要。
十六、为什么 ORDER BY 优化建议尽量使用覆盖索引?
例如查询:
sql
SELECT id, age, phone
FROM tb_user
ORDER BY age, phone;
如果索引能够覆盖查询需要的数据,就有机会:
text
扫描索引
↓
得到排序结果
↓
直接取得需要的列
从而减少额外的数据页访问。
反之,如果查询:
sql
SELECT *
FROM tb_user
ORDER BY age, phone;
即使排序字段有索引,也可能因为需要获取大量不在索引中的字段,增加回表访问成本。
因此:
ORDER BY 优化不仅需要考虑排序字段是否建立索引,还应该考虑查询字段能否合理地被索引覆盖。
但也不要为了覆盖所有查询而无限扩展索引,因为索引越多、越宽,会增加:
- 存储空间;
- INSERT 成本;
- UPDATE 成本;
- DELETE 成本;
- 索引维护成本。
MySQL 官方同样强调,应在查询性能与索引维护成本之间取得平衡。 (MySQL开发者专区)
十七、ORDER BY 索引优化思维图
可以把整个判断流程记成:
text
ORDER BY
│
↓
排序字段有没有合适索引?
│ │
否 是
│ │
↓ ↓
Using filesort 字段顺序匹配吗?
│
┌───────┴───────┐
│ │
否 是
│ │
↓ ↓
Using filesort 排序方向匹配吗?
│
┌───────┴───────┐
│ │
否 是
│ │
↓ ↓
创建匹配 ASC/DESC 利用索引顺序
的联合索引
因此,ORDER BY 索引设计实际上主要需要看三个维度:
text
字段
+
字段顺序
+
ASC / DESC 方向
十八、如果 Using filesort 无法避免怎么办?
并不是所有排序查询都值得建立专门索引。
例如:
text
排序条件组合很多
临时统计查询很多
低频查询
排序字段变化非常频繁
如果为了所有 ORDER BY 都创建一个联合索引,会产生大量冗余索引。
因此某些场景下:
text
Using filesort
是可以接受的。
当 filesort 无法通过 SQL 和索引设计消除,并且排序数据量比较大时,可以进一步关注:
text
sort_buffer_size
十九、sort_buffer_size 是什么?
sort_buffer_size 是 MySQL 用于排序操作的缓冲区相关参数。
可以查看:
sql
SHOW VARIABLES LIKE 'sort_buffer_size';
MySQL 8.0 官方文档给出的默认值为:
text
262144 bytes
也就是:
text
256 KB
如果大量排序无法通过索引优化,并出现较多排序合并操作,可以评估是否适当增大该参数。 (MySQL开发者专区6)
二十、sort_buffer_size 是不是越大越好?
不是。
不要简单地执行:
text
排序慢
↓
把 sort_buffer_size 调到很大
因为该缓冲区与执行排序的会话相关。
如果全局设置过大,同时存在大量并发排序:
text
单连接排序内存
×
并发连接数量
就可能产生比较大的内存压力。
MySQL 官方文档也建议不要盲目把该值全局设置得很大,更适合针对实际负载测试后调整。 (MySQL开发者专区6)
因此正确优化顺序应该是:
text
① 优化 SQL
↓
② 优化索引
↓
③ 减少排序数据量
↓
④ 最后再考虑排序参数
而不是:
text
一看到 Using filesort
↓
直接修改 sort_buffer_size
二十一、完整案例总结
假设:
text
tb_user
包含:
text
id
age
phone
场景 1:没有索引
sql
EXPLAIN
SELECT id, age, phone
FROM tb_user
ORDER BY age, phone;
可能出现:
text
Using filesort
场景 2:建立联合索引
sql
CREATE INDEX idx_user_age_phone_aa
ON tb_user(age, phone);
执行:
sql
EXPLAIN
SELECT id, age, phone
FROM tb_user
ORDER BY age, phone;
此时具备利用索引顺序避免额外排序的条件。
场景 3:全部降序
sql
EXPLAIN
SELECT id, age, phone
FROM tb_user
ORDER BY age DESC, phone DESC;
可以通过反向扫描:
text
Backward index scan
利用相同的联合索引顺序。
场景 4:调换字段顺序
sql
EXPLAIN
SELECT id, age, phone
FROM tb_user
ORDER BY phone, age;
由于:
text
索引:
age → phone
查询:
phone → age
顺序不匹配,因此可能:
text
Using filesort
场景 5:一升一降
sql
EXPLAIN
SELECT id, age, phone
FROM tb_user
ORDER BY age ASC, phone DESC;
现有索引:
text
(age ASC, phone ASC)
无法完全满足排序方向,因此可能:
text
Using filesort
场景 6:建立混合方向索引
sql
CREATE INDEX idx_user_age_phone_ad
ON tb_user(age ASC, phone DESC);
然后:
sql
EXPLAIN
SELECT id, age, phone
FROM tb_user
ORDER BY age ASC, phone DESC;
即可让索引方向与查询排序方向匹配。
二十二、ORDER BY 性能优化的正确排查步骤
线上遇到慢排序 SQL 时,可以按照以下顺序排查。
第一步:使用 EXPLAIN
sql
EXPLAIN
SELECT ...
FROM ...
ORDER BY ...;
重点观察:
text
key
rows
Extra
尤其是:
text
Using filesort
第二步:检查排序字段
例如:
sql
ORDER BY age, phone
确认是否存在:
text
(age, phone)
这样的合适索引。
第三步:检查联合索引字段顺序
索引:
text
(age, phone)
不等于:
text
(phone, age)
因此不能看到字段都在索引中,就认为一定能优化排序。
第四步:检查 ASC / DESC
查询:
sql
ORDER BY age ASC, phone DESC
需要重点检查索引方向是否与排序要求匹配。
第五步:检查能否使用覆盖索引
尽量避免不必要的:
sql
SELECT *
只查询业务真正需要的列。
第六步:最后再考虑 sort_buffer_size
如果索引已经无法进一步优化,而且确实存在大量排序,再结合:
text
Sort_merge_passes
并发连接数
单次排序数据量
服务器内存
评估排序缓冲区参数。
二十三、ORDER BY 优化的 4 条核心原则
最终可以总结成下面四条。
1. 根据排序字段建立合适索引
例如:
sql
ORDER BY age, phone
可以考虑:
sql
INDEX(age, phone)
2. 多字段排序注意索引字段顺序
索引:
text
(age, phone)
更适合:
sql
ORDER BY age, phone
而不是:
sql
ORDER BY phone, age
3. 尽量使用覆盖索引
在满足业务需求的前提下,只查询真正需要的字段,尽量减少不必要的回表。
4. ASC / DESC 混合时注意索引方向
如果长期存在:
sql
ORDER BY age ASC, phone DESC
可以考虑:
sql
INDEX(age ASC, phone DESC)
二十四、FAQ:MySQL ORDER BY 常见问题
1. MySQL ORDER BY 如何优化?
最主要的方法是:
根据 ORDER BY 的字段、字段顺序和排序方向建立合适的联合索引,让 MySQL 尽可能利用索引顺序返回数据,从而避免额外的 filesort。
同时可以配合覆盖索引减少回表。
2. Using filesort 是什么意思?
Using filesort 表示 MySQL 无法完全通过索引顺序满足 ORDER BY,需要执行额外的排序过程。
它不代表一定进行了磁盘排序。
3. Using filesort 一定很慢吗?
不一定。
性能取决于:
- 排序数据量;
- 是否需要磁盘临时文件;
LIMIT大小;- 内存;
- 数据分布;
- 查询并发量。
但是对于高频、大数据量查询,如果可以利用合适的索引消除 filesort,通常值得优化。
4. Using index 是什么意思?
Using index 主要表示:
查询所需要的数据可以从索引树中直接获得,也就是覆盖索引。
它并不等价于:
text
ORDER BY 一定没有额外排序
判断排序是否进行了 filesort,应该重点查看:
text
Using filesort
5. Using index; Using filesort 能同时出现吗?
可以。
例如:
text
Using index; Using filesort
表示:
查询列能够通过覆盖索引获得,但是 ORDER BY 仍然需要额外排序。
6. ORDER BY age DESC, phone DESC 能走 (age, phone) 索引吗?
可以。
当索引为:
text
(age ASC, phone ASC)
时,可以通过反向扫描得到:
text
(age DESC, phone DESC)
7. 为什么 ORDER BY age ASC, phone DESC 可能不能使用普通联合索引排序?
因为普通:
text
(age ASC, phone ASC)
索引无法通过简单的正向或反向扫描同时满足:
text
age ASC
phone DESC
这种混合排序方向。
可以考虑建立:
sql
INDEX(age ASC, phone DESC)
8. ORDER BY phone, age 能使用 (age, phone) 索引吗?
通常不能直接使用该索引完成完整排序。
因为:
text
(age, phone)
保证的是:
text
先 age
再 phone
而不是:
text
先 phone
再 age
9. sort_buffer_size 越大越好吗?
不是。
应该优先优化:
text
SQL
↓
索引
↓
查询数据量
确实无法避免大量 filesort 后,再针对实际负载评估 sort_buffer_size。
二十五、一张表总结 MySQL ORDER BY 优化
| 问题 | 推荐方案 |
|---|---|
| 排序字段没有索引 | 为高频排序建立合适索引 |
| 多字段排序 | 建立联合索引 |
| 字段顺序不匹配 | 调整联合索引字段顺序 |
| 全部 ASC | 正向扫描索引 |
| 全部 DESC | 可反向扫描索引 |
| ASC + DESC 混合 | 建立对应方向的混合索引 |
| 查询字段较少 | 考虑覆盖索引 |
出现 Using filesort |
检查是否能通过索引消除 |
| filesort 无法避免 | 再评估 sort_buffer_size |
| 不确定是否优化成功 | 使用 EXPLAIN 验证 |
二十六、30 秒记住 ORDER BY 优化
最后把整节内容压缩成一段:
text
MySQL ORDER BY 优化的核心是利用索引本身的有序性。
如果 ORDER BY 无法利用索引顺序,
EXPLAIN 中通常会看到 Using filesort。
对于多字段排序:
字段顺序要与联合索引匹配;
全部 ASC 或全部 DESC 可以利用同一索引正向/反向扫描;
ASC、DESC 混合时需要关注联合索引的排序方向。
同时尽量使用覆盖索引减少回表。
如果 filesort 无法通过 SQL 和索引设计避免,
再考虑 sort_buffer_size 等排序相关参数。
二十七、总结
MySQL ORDER BY 优化并不是简单地:
text
给排序字段加一个索引
真正需要同时考虑:
text
排序字段
+
联合索引顺序
+
ASC / DESC 方向
+
查询字段是否可以覆盖
最关键的判断方法还是:
sql
EXPLAIN
重点关注:
text
Using filesort
如果能够利用合适的 B+Tree 索引直接获得有序结果,就可以避免额外排序。
最终记住:
ORDER BY 优化的本质,就是尽量把"运行时重新排序"转变为"直接读取已经有序的索引"。
这也是处理 MySQL 排序性能问题时最重要的优化思路。
若有转载:请标明出处:https://blog.csdn.net/CharlesYuangc/article/details/164186003