DESC索引仅在ORDER BY方向与索引定义逐列严格一致且WHERE满足最左前缀时才跳过filesort;单列DESC索引对纯ORDER BY created_at DESC查询常因优化器不选反向扫描而失效,带范围条件更会完全失效;真实分页需联合索引如INDEX(status, created_at DESC),并补唯一列(如id)防重复。
索引不是分页乱序或慢的万能解药,它只在
ORDER BY 方向与索引定义逐列严格一致 + WHERE 满足最左前缀
时才能跳过
;否则你建的
和没建几乎一样。
为什么加了
还是
这是最常被误判的点:单列降序索引对纯
查询,在多数情况下根本用不上排序能力。
MySQL 8.0 对单列
索引执行倒序扫描时,实际走的是
(反向遍历 B+ 树),但优化器往往不选它——尤其当表数据量不大、或统计信息不准时,它宁可全表扫 +
中出现
就说明没走索引排序;哪怕
字段显示你建的索引名,只要
里有这个字样,就等于白建
更隐蔽的坑:
这类范围条件,会直接让单列
索引失效于排序——B+ 树无法同时满足“范围过滤”和“倒序读取”的物理顺序要求
才是分页场景的正确姿势
真实业务分页几乎都带过滤条件,比如
。这时必须把等值列放前面、排序列放后面,并明确标
。
MySQL(Linux)
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
下载
索引定义必须和查询完全对齐:
→ 只加速
;换成
或漏掉
,索引就退化为普通查找
验证是否生效,盯紧三处:
显示该索引名、
是
或
、
里没有
(最好还有
)
如果
条件含
或多个等值项(如
),MySQL 8.0.20+ 才较稳定支持该索引用于排序;低版本可能仍触发
对比执行计划:一眼识别降序索引是否真起作用
别只看
字段,重点比对
和
的变化。
建索引前:
或
,
≈ 表总行数,
建
后:
,
缩小到匹配
的行数,
变成
(无
)——这才是有效命中
用
更直观:能看到
,表示跳过了排序节点;若看到
,说明还是在内存/磁盘里排
分页稳定性比速度更关键:别忘了唯一性补丁
即使
让排序变快,
仍可能跨页重复——因为多个记录的
完全相同。
解决方法不是加更多索引,而是补上唯一列:
,并确保索引包含
(如
)
否则第一页最后一条和第二页第一条时间戳一样,数据库按任意顺序返回,前端就看到重复或漏数据
这个细节在压测和线上灰度时才暴露,但修复成本极低:改 SQL + 扩展索引,无需动业务逻辑
DESCfilesortINDEX (created_at DESC)INDEX (created_at DESC)Using filesortORDER BY created_at DESC LIMIT 20DESCBackward index scanfilesortEXPLAINExtra: Using filesortkeyExtraWHERE created_at > '2025-01-01'DESCINDEX (status, created_at DESC)WHERE status = 'done' ORDER BY created_at DESC LIMIT 20DESCINDEX (status ASC, created_at DESC)WHERE status = ? ORDER BY created_at DESCORDER BY created_at ASCstatus = ?keytyperefrangeExtraUsing filesortUsing indexWHEREINstatus IN ('done','pending')filesortkeyExtrarowstype: ALLtype: indexrowsExtra: Using filesortINDEX (status, created_at DESC)type: refrowsstatusExtraUsing indexfilesortEXPLAIN FORMAT=TREE-> Sort row sources: false-> SortINDEX (status, created_at DESC)ORDER BY created_at DESC LIMIT 20,10created_atORDER BY created_at DESC, id DESCidINDEX (status, created_at DESC, id DESC)