降序索引仅在WHERE条件、ORDER BY方向与索引定义三者逐列严格对齐时才生效,否则无效甚至拖慢写入;MySQL 8.0.12+才真正支持物理降序存储,需通过SHOW CREATE TABLE和INFORMATION_SCHEMA验证DESC字样及D排序规则,且必须有最左等值条件锚定扫描起点,方向不匹配或缺失锚点均触发filesort。

降序索引不是“建了就快”,它只在 WHERE 条件、ORDER BY 方向、索引定义三者**逐列严格对齐**时,才能真正跳过 Using filesort;其他情况建了白建,甚至拖慢写入。
确认 MySQL 版本和索引是否真被物理存储
MySQL 8.0.11 及更早版本会静默忽略 DESC,哪怕你写了 INDEX (a DESC),实际建出来的仍是升序索引。必须满足:
-
SELECT VERSION()返回 ≥8.0.12 -
SHOW CREATE TABLE t输出中明确出现col_name DESC字样(不是只有列名) -
SELECT COLLATION FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_NAME = 't' AND INDEX_NAME = 'idx'返回D(A表示升序)
特别注意:PRIMARY KEY (id DESC) 在 8.0.11 及之前仍会被强制转成升序,别信语法糖。
WHERE 必须提供最左前缀等值匹配
降序部分不能“孤军奋战”,它需要前面的等值条件锚定扫描起点。没有这个锚点,DESC 就失效。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- ✅ 有效:
WHERE status = 'done' ORDER BY created_at DESC→ 配合INDEX (status, created_at DESC) - ❌ 无效:
WHERE status IN ('done', 'pending') ORDER BY created_at DESC(8.0.19 及更早大概率仍Using filesort) - ❌ 无效:
WHERE created_at > '2025-01-01' ORDER BY created_at DESC(单列范围 + 降序 = B+ 树物理顺序冲突,优化器倾向放弃) - ❌ 无效:
WHERE status = 'done' AND priority > 5 ORDER BY created_at DESC(priority > 5中断最左前缀连续性)
ORDER BY 必须与索引方向逐列完全一致
MySQL 不会“部分复用”混合方向索引。方向错一位、少一位、多一位,整个排序逻辑就断掉,必然触发 Using filesort。
- 索引是
(a ASC, b DESC)→ 只加速ORDER BY a, b DESC或纯ORDER BY a - 索引是
(a DESC, b ASC)→ 不支持ORDER BY a DESC, b DESC,也不支持ORDER BY b ASC - 索引是
(a DESC, b DESC)→ 对应ORDER BY a DESC, b DESC,别指望它也能服务ASC查询 - 同一列不能重复声明方向,如
(a ASC, a DESC)直接报错ERROR 1064
验证降序索引是否真正在工作
光看 EXPLAIN 的 key 字段命中索引名远远不够,关键盯三处:
-
Extra列不能出现Using filesort或Using temporary -
type应为ref或range(不是ALL或index),且rows显著小于总行数(比如百万级表降到几千) - 若查询含
SELECT *,尤其含TEXT字段,MySQL 更倾向全字段排序;优先用SELECT id, status, created_at+ 覆盖索引
MySQL 8.0.20+ 可用 EXPLAIN FORMAT=TREE,直接看执行计划里有没有 -> Sort 节点;没有,才说明排序已下推到索引层。
最容易被忽略的是:单列 DESC 索引配合范围查询基本无效,而联合索引中任意列方向变化都意味着一套新物理结构——空间和维护成本都翻倍,别盲目堆索引。

















