MySQL 8.0.12+ 才真正支持索引定义中的 DESC 生效;8.0.11 及更早版本会静默忽略,建出的仍是升序索引,需通过 SHOW CREATE TABLE 或 INFORMATION_SCHEMA.STATISTICS 中 COLLATION = 'D' 验证。

倒序索引不是建了就能用,必须让 ORDER BY 的列顺序和方向与索引定义完全一致,否则 MySQL 8.0 仍会走 filesort。
建索引时写 DESC 真的生效吗?
MySQL 8.0.12+ 才真正支持 DESC 在索引定义中落地;8.0.11 及更早版本会静默忽略,建出来还是升序索引。验证方式很简单:
- 执行
SHOW CREATE TABLE table_name,确认输出里是否保留了col_name DESC - 查系统表:
SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 'your_table' AND INDEX_NAME = 'your_idx',看COLLATION字段是否为D(升序是A) - 在 MySQL 8.0.20+ 上用
EXPLAIN FORMAT=TREE,直接看执行计划里有没有filesort节点
ORDER BY a DESC, b ASC 能不能用 INDEX (a DESC, b DESC)?
不能。方向必须逐列严格匹配——b ASC 和 b DESC 是两个物理上不兼容的排序序列。InnoDB 对降序索引的存储是反向键值编码(比如字符串按字节逆序),ASC 和 DESC 索引无法共享底层 B+ 树结构。
常见错误场景:
- 只建了
INDEX (updated_at DESC),但查询是WHERE status = 'done' ORDER BY updated_at DESC→ 缺少最左前缀,索引完全无效 - 建了
INDEX (user_id, created_at DESC),但查询是ORDER BY created_at DESC且没带WHERE user_id = ?→ 优化器无法跳过前导列,大概率退化为全索引扫描 - 写
ORDER BY DATE(created_at) DESC→ 函数表达式强制索引失效,降序索引也救不了
怎么确认倒序索引真正在工作?
光看 EXPLAIN 的 key 字段命中不够,关键盯紧三处:
-
Extra列不能出现Using filesort或Using temporary -
type应为ref、range或index,而非ALL -
rows值应明显小于表总行数(比如从百万级降到几千)
如果 EXPLAIN 显示 Backward index scan,说明优化器用了反向扫描升序索引——这是 5.7 的 fallback 行为,不是 8.0 倒序索引生效的标志。
比建倒序索引更该先做的事
多数“倒序慢”问题根源不在索引方向,而在设计前提没对齐:
- 先检查
WHERE条件是否构成索引最左前缀:比如WHERE status = 'active' ORDER BY updated_at DESC,索引必须是(status, updated_at DESC),而不是单列(updated_at DESC) - 确认没有隐式类型转换:
WHERE id = '123'(id 是INT)会让整个索引失效 - 避免
SELECT *+LIMIT组合:即使有索引,优化器也可能误判成本而选全表扫描;优先改写成覆盖索引查询,例如SELECT id, title FROM posts ORDER BY created_at DESC LIMIT 20,再建(created_at DESC, id, title)
降序索引本身要占额外空间(ASC 和 DESC 索引物理不复用),建之前得算清楚:这个查询是否高频、是否真的卡在排序阶段、有没有更轻量的替代方案(比如时间分片 or 游标分页)。


















