order by 能否走索引取决于查询条件与排序字段是否被同一索引覆盖:需满足最左前缀原则、无函数/表达式、无隐式转换,且索引列顺序严格匹配排序顺序;where 条件位置影响索引有序扫描能力,覆盖索引可同时避免回表和文件排序。

ORDER BY 能否走索引,不只看有没有索引,关键看查询条件和排序字段是否能被同一个索引“覆盖”——即满足最左前缀原则且无中断、无函数/表达式干扰、无类型隐式转换。
索引列顺序必须严格匹配 ORDER BY 顺序
MySQL 只能利用索引的有序性来避免文件排序(Using filesort)。如果索引是 (a, b, c),那么以下 ORDER BY 可走索引:
- ORDER BY a
- ORDER BY a, b
- ORDER BY a, b, c
但 ORDER BY b、ORDER BY a, c(跳过 b)、ORDER BY b, c 都无法利用该索引排序。即使 WHERE 中用了 a,排序仍需回表或 filesort。
WHERE 条件会“截断”索引可用长度
索引 (user_id, create_time, status),若查询写成:
SELECT * FROM orders WHERE status = 1 ORDER BY user_id, create_time;
此时 WHERE 条件在最右列,索引无法按 user_id + create_time 有序扫描——因为 status = 1 不是索引最左前缀,MySQL 实际可能全索引扫描再过滤,排序仍不可下推。正确写法应让过滤列靠左:
- WHERE user_id = 123 ORDER BY create_time → 可走索引
- WHERE user_id = 123 AND status = 1 ORDER BY create_time → 仍可走索引(status 是等值,不破坏顺序)
避免在 ORDER BY 字段上做任何计算或类型转换
哪怕只是加个 UPPER()、DATE(create_time)、col + 0 或隐式转换(如字符串列与数字比较),都会导致索引失效。例如:
- ORDER BY UPPER(name) → 索引失效
- ORDER BY create_time DESC → 可用索引(只要索引本身支持反向扫描,InnoDB 支持)
- ORDER BY create_time DESC, id ASC → 若索引为 (create_time, id),则仅当两者方向一致或 MySQL 8.0+ 支持混合方向时才可能生效;旧版本要求全部同向
覆盖索引 + ORDER BY 可彻底避免回表和排序
如果 SELECT 的字段、WHERE 条件字段、ORDER BY 字段,全部包含在同一个索引中,且顺序合理,就能实现“索引覆盖 + 索引排序”双重优化。例如:
SELECT user_id, create_time FROM orders WHERE user_id BETWEEN 100 AND 200 ORDER BY create_time;
配合索引 (user_id, create_time),即可: - 快速定位 user_id 范围(索引范围扫描) - 按 create_time 天然有序返回(无需 filesort) - 所有字段都在索引里(无需回表)
这种组合是最高效的 ORDER BY 优化形态。










