ORDER BY 字段必须是索引的最左前缀
MySQL 只有在
ORDER BY子句中的字段,**严格匹配索引定义的最左连续列**时,才能利用索引避免文件排序(
Using filesort)。哪怕只多一个非连续字段,或顺序不一致,优化器大概率会放弃索引排序。
比如有复合索引
INDEX idx_user_status_created (status, created_at):
ORDER BY status, created_at✅ 走索引
ORDER BY status✅ 走索引(最左前缀)
ORDER BY created_at❌ 不走索引排序(跳过
status)
ORDER BY status DESC, created_at ASC❌ 多数版本不走索引(升序/降序混用,8.0+ 支持但需显式定义)
避免 SELECT * 与覆盖索引冲突
即使
ORDER BY字段有索引,如果查询中包含大量非索引字段(如
SELECT *),MySQL 仍可能放弃索引排序——因为回表成本高,优化器觉得全表扫描 + filesort 更快。
更稳妥的做法是:让索引「覆盖」查询所需全部字段(即覆盖索引)。
原语句:SELECT id, name, email FROM users WHERE status = 'active' ORDER BY created_at;对应索引应为:
INDEX idx_status_created_cover (status, created_at, id, name, email)这样既满足
WHERE status = ...过滤,又满足
ORDER BY created_at,还能避免回表
注意 LIMIT 对执行计划的影响
LIMIT本身不会让 MySQL 自动选择排序索引,但它会影响优化器对“取前 N 行是否值得用索引排序”的判断。尤其当
WHERE条件匹配行数远大于
LIMIT值时,使用索引排序 +
LIMIT往往显著更快。
但要注意:如果
WHERE条件太宽泛(例如无有效过滤),MySQL 可能仍选错执行路径。 检查是否真的用了索引排序:
EXPLAIN SELECT * FROM orders WHERE user_id > 1000 ORDER BY created_at DESC LIMIT 20;关键看
Extra列:出现
Using filesort就说明没走索引排序 若
type是
index且
key显示用了排序索引,通常靠谱
ASC/DESC 在索引定义中要显式声明(MySQL 8.0+)
MySQL 8.0 之前,索引默认按升序存储,
ORDER BY ... DESC无法利用普通 B-Tree 索引做排序;8.0+ 支持在建索引时指定方向,但必须显式写出,否则仍不生效。
错误写法:
CREATE INDEX idx_time ON events(created_at);→ 无法支持
ORDER BY created_at DESC排序优化
正确写法:
CREATE INDEX idx_time_desc ON events(created_at DESC);
注意:如果同时需要
ASC和
DESC查询,目前只能建两个索引,或接受其中一种走
filesort。
索引排序不是“建了就能用”,它高度依赖字段顺序、查询写法、版本特性,以及优化器对成本的估算。最容易被忽略的是:明明建了索引,
EXPLAIN却显示
Using filesort—— 先确认
ORDER BY是否命中最左前缀,再查是否因
SELECT字段过多导致放弃索引,最后看版本和排序方向是否匹配。
