DESC索引仅在WHERE最左列等值匹配、ORDER BY方向逐列严格一致、SELECT列被索引覆盖三条件同时满足时才跳过filesort;否则无效甚至拖慢写入。

DESC 索引不是建了就提速,它只在 WHERE 最左列等值匹配 + ORDER BY 方向逐列严格一致 + SELECT 列被索引覆盖 这三个条件同时满足时,才能真正跳过 Using filesort;缺一不可,否则白建,甚至拖慢写入。
怎么确认你的 DESC 索引真的生效了
光看EXPLAIN 的 key 字段命中索引名没用,关键盯三处:
• Extra 字段不能出现 Using filesort 或 Using temporary
• type 应为 ref、range 或 index,不能是 ALL
• rows 值必须明显小于表总行数(比如百万级表降到几千)
• MySQL 8.0.20+ 可用 EXPLAIN FORMAT=TREE,直接看执行计划里有没有 -> Sort 节点
验证物理存储是否真按降序建:运行 SHOW CREATE TABLE t,输出中必须明确出现类似 created_at DESC;更准的方式是查系统表:SELECT COLLATION FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't' AND INDEX_NAME = 'idx',结果为 D 才代表落地成功。
ORDER BY a DESC, b ASC 必须配 INDEX (a DESC, b ASC)
方向错一位、少一位、多一位,整个排序逻辑就失效——不是“部分生效”,而是彻底不走索引排序。
• INDEX (a DESC, b DESC) 对 ORDER BY a DESC, b ASC 完全无效
• INDEX (a ASC, b DESC) 和 ORDER BY a DESC, b ASC 物理结构不兼容,无法复用
• 联合索引中每列的 ASC/DESC 必须和 ORDER BY 子句逐列严格一致;建议显式写出 ASC,避免歧义
MySQL 不会 fallback:一旦方向不匹配,优化器不会尝试用升序索引倒扫,而是直接走 filesort 或全表扫描。
单列 DESC 索引 + WHERE 范围条件基本无效
这是最常踩的坑:
• 建了 INDEX (updated_at DESC),又写 WHERE updated_at > '2025-01-01' ORDER BY updated_at DESC,以为能又过滤又排序——实际 B+ 树无法同时满足范围定位和倒序读取的物理顺序要求,往往退化为全索引扫描
• 真正有效的组合是「高选择性等值条件 + 排序列 DESC」,例如:WHERE status = 'done' AND updated_at > '2025-01-01' ORDER BY updated_at DESC
• 对应索引必须是 INDEX (status, updated_at DESC),把等值列放最左,后续才能复用排序能力
纯 ORDER BY created_at DESC LIMIT 20 查询,即使建了单列 DESC 索引,优化器也大概率选全表扫描或聚簇索引扫描,而非反向遍历该索引。
为什么建了 DESC 索引反而变慢
这不是 bug,是设计代价被忽略的结果:
• 空间翻倍:INDEX (a ASC) 和 INDEX (a DESC) 是两套独立物理结构,InnoDB 不复用
• 维护开销增加:每次 INSERT/UPDATE 都要按反向规则编码键值,对高写入表有轻微影响
• 优化器误选:当统计信息不准,或查询带函数(如 ORDER BY DATE(created_at) DESC),降序索引直接失效,且无法 fallback 到升序索引,只能全表扫 + filesort
最容易被忽略的是:单列 DESC 索引遇上范围查询基本无效;而联合索引中任意列方向变化,都意味着一套新索引——别指望一个 INDEX (a, b DESC) 能同时加速 ORDER BY a, b DESC 和 ORDER BY a, b ASC。



















