mysql 8.0 降序索引仅在严格匹配等值条件+方向一致的 order by 时跳过 filesort,否则无效甚至更慢;explain 出现 using filesort 即未生效,且 asc/desc 必须完全对齐,无法双向复用。

不能一概而论——MySQL 8.0 的降序索引 INDEX (col DESC) 只在极少数严格匹配的查询中跳过 Using filesort,否则不仅不提速,还可能更慢。
EXPLAIN 里还有 Using filesort 就说明没生效
这是最直接的判断依据。只要 EXPLAIN 的 Extra 字段出现 Using filesort,无论你建了多少个 DESC 索引,MySQL 都得把数据捞出来再排序。
- 常见错误现象:
CREATE INDEX idx_status_created ON orders (status, created_at DESC),但查询写成SELECT * FROM orders WHERE status IN ('pending', 'processing') ORDER BY created_at DESC—— 因为WHERE status IN ()是范围条件,断掉了排序能力传递,created_at DESC部分完全失效 - 真正能走索引排序的写法必须是等值匹配最左列:
WHERE status = 'done',且ORDER BY必须逐列方向一致:ORDER BY status, created_at DESC -
SELECT *容易触发回表,若包含大字段(如TEXT),MySQL 8.0 更倾向全字段排序,可能直接落盘出现Using disk sort
联合索引中 ASC/DESC 必须和 ORDER BY 完全对齐
MySQL 只能按索引定义的物理顺序前向扫描,无法中途翻转方向。
-
CREATE INDEX idx ON t(a ASC, b DESC)只支持ORDER BY a ASC, b DESC或ORDER BY a ASC;不支持ORDER BY a ASC, b ASC,也不支持ORDER BY a DESC, b DESC -
CREATE INDEX idx ON t(a DESC, b ASC)和上面那个索引物理结构完全不同,不能互相替代 - 试图用单个索引覆盖双向排序(比如既要
ORDER BY updated_at DESC又要ORDER BY updated_at ASC)是不可能的——B+ 树叶子节点的物理顺序只能是一种
建了降序索引反而变慢的三个现实原因
它不是免费加速器,而是有明确代价的设计选择。
- 空间翻倍:
INDEX (a ASC)和INDEX (a DESC)是两套独立物理结构,InnoDB 不复用;混合方向联合索引(如(a ASC, b DESC))也不能替代(a DESC, b ASC) - 写入开销增加:每次
INSERT/UPDATE都要按反向规则编码键值,高写入场景下有可测延迟 - 优化器误选风险:一旦
ORDER BY含函数(如ORDER BY DATE(created_at) DESC),降序索引直接失效,且无法 fallback 到升序索引,只能全表扫 +filesort
真正该优先检查的,往往不是索引方向
多数“倒序慢”的问题,根源不在要不要加 DESC,而在基础条件是否满足。
- 先确认
WHERE条件是否提供了高选择性的等值匹配(=或IS NULL),而不是>、IN、BETWEEN - 检查是否有隐式类型转换,比如
WHERE id = '123'(id是INT)会强制全表扫描 - 用
sys.schema_unused_indexes查查已有索引里哪些根本没人用,别一边建新索引一边养着一堆僵尸索引 - 如果业务同时需要
ASC和DESC分页,老老实实建两个索引比硬凑一个“万能”索引更可靠
降序索引的关键价值,是让某些高频固定模式的查询(比如后台列表页的“最新 20 条”)能稳定避开 filesort;但它对查询写法极其敏感,稍有偏差就退回原点。别把它当成通用加速开关,而应看作一种精准匹配的执行路径控制手段。











