mysqlorder by如何利用索引_mysql排序优化技巧

来源:这里教程网 时间:2026-02-28 20:48:38 作者:

ORDER BY 字段必须是索引的最左前缀

MySQL 只有在

ORDER BY
子句匹配索引的**连续最左列**时,才能避免文件排序(
Using filesort
)。比如有联合索引
INDEX (a, b, c)
,以下写法能走索引:

ORDER BY a
ORDER BY a, b
ORDER BY a, b, c

ORDER BY b
ORDER BY a, c
(跳过
b
)、
ORDER BY b, c
都无法利用该索引做排序。注意:即使
a
=
条件,
ORDER BY b, c
仍大概率触发
Using filesort
—— 因为索引中
a
值相等的记录,
b, c
部分才是有序的,而优化器通常不认为这足够“全局有序”。

避免混合 ASC/DESC 导致索引失效

MySQL 8.0 之前,如果联合索引定义为

INDEX (a ASC, b ASC)
,而查询写成
ORDER BY a ASC, b DESC
,就无法使用该索引排序(会回退到
Using filesort
)。MySQL 8.0+ 支持降序索引,可显式建为
INDEX (a ASC, b DESC)
,此时
ORDER BY a ASC, b DESC
才能命中。

检查执行计划:出现
Using filesort
就说明没走索引排序
旧版本想兼容混合方向,只能建两个索引(如
(a,b)
(a,b DESC)
),但后者在 5.7 及以前语法不合法
DESC
在索引定义中不是注释,是真实存储方向,影响 B+ 树遍历顺序

WHERE + ORDER BY 组合时,索引要覆盖过滤和排序需求

典型陷阱:给

WHERE status = 1
建了
INDEX (status)
,又想
ORDER BY created_at
,结果还是
Using filesort
—— 因为单列索引
status
不含
created_at
,无法排序。

应建联合索引:
INDEX (status, created_at)
(注意顺序:先 where 列,再 order by 列)
如果还有
SELECT *
或需要返回其他字段,考虑是否加覆盖索引,避免回表(例如
INDEX (status, created_at, id, name)
WHERE
条件用的是范围(如
status > 0
),则
ORDER BY
后续列**无法使用索引排序**(B+ 树中范围扫描后的数据不再保证有序)

小结果集别强求索引排序,大分页慎用 LIMIT offset

ORDER BY id LIMIT 10
这类小结果,即使没走索引排序,成本也极低;但
ORDER BY created_at LIMIT 10000, 20
会让 MySQL 先排序前 10020 行,再丢弃前 10000 行 —— 即使
created_at
有索引,I/O 和 CPU 开销依然巨大。

改用游标分页:
WHERE created_at 
如果必须跳转,考虑用延迟关联(
SELECT * FROM t JOIN (SELECT id FROM t ORDER BY x LIMIT 10000,20) AS tmp USING(id)
)减少排序行数
SQL_BUFFER_RESULT
有时能缓解,但治标不治本

真正难优化的,往往不是“有没有索引”,而是“索引列顺序是否贴合查询模式”以及“范围条件之后还能不能排序”。这两个点漏掉一个,

EXPLAIN
里就稳稳写着
Using filesort

相关推荐