explain显示using filesort说明mysql未用索引排序,而是额外内存或磁盘排序;必须确保order by字段构成联合索引最左连续前缀,且避免范围查询、函数、混合升降序等破坏索引有序性的操作。
explain 显示 using filesort 就是没走索引
navicat 里右键 sql → “解释”,如果 extra 列出现 using filesort,说明 mysql 正在内存或磁盘上做二次排序,索引根本没被用于排序。这不是 navicat 的 bug,而是 mysql 执行计划的真实反馈。
- 别信“表不大所以无所谓”——哪怕只有 1 万行,
Using filesort在高并发下也会迅速拖垮响应 -
type=ALL+Using filesort组合,基本等于全表扫描后再排序,性能灾难 - Navicat 16.0.x 某些版本(≤16.0.12)会错误隐藏
key字段值,建议用命令行执行EXPLAIN FORMAT=JSON SELECT ...验证
ORDER BY 字段没进联合索引最左连续前缀
单独给 created_at 建索引,对 WHERE status = ? ORDER BY created_at DESC 没用。MySQL 要求排序字段必须构成索引的**最左连续前缀**,且不能跳过前面字段。
- 正确建法:
CREATE INDEX idx_status_created ON orders(status, created_at)—— 等值条件字段status放前,排序字段created_at紧跟其后 - 错误建法:
CREATE INDEX idx_created_status ON orders(created_at, status)——created_at在前,但WHERE条件没用它,整个索引对这个查询无效 - 复合排序如
ORDER BY a ASC, b DESC:MySQL 8.0+ 才支持显式方向定义,且必须写成INDEX (a ASC, b DESC);5.7 及以前只要含DESC,基本放弃索引排序
SELECT * 或字段太多导致优化器弃用索引排序
即使 ORDER BY 字段有索引,如果 SELECT 的字段太多、尤其含大字段(TEXT、BLOB),MySQL 可能判定“回表成本太高”,宁愿用 Using filesort。
- Navicat 默认执行
SELECT *,而你真正需要的可能只是id, title, created_at - 验证方式:把
SELECT *改成只查索引覆盖的字段(比如联合索引里的全部列),再看EXPLAIN是否还出现Using filesort - 若仍不走索引,说明不是回表问题,得回头检查隐式转换、函数包裹或统计信息是否过期
统计信息陈旧让优化器误判索引价值
Navicat 同步、还原或大批量导入数据后,InnoDB 的统计信息不会自动更新。EXPLAIN 显示 rows 远大于实际匹配数,或 possible_keys 有值但 key 为空,大概率是这个原因。
- 立刻执行:
ANALYZE TABLE orders;—— 毫秒级,无锁,只刷新采样统计,不移动数据 - 别用 Navicat 的「维护 → 重新优化表」:它执行的是
OPTIMIZE TABLE,会重建整张表,大表要卡几分钟,纯属浪费 - 超大表(千万级)采样不准?MySQL 8.0+ 可加参数:
ANALYZE TABLE orders UPDATE HISTOGRAM ON created_at;
真正卡住的点往往不在“建没建索引”,而在“建了但 MySQL 不信它有用”。ANALYZE TABLE 是最轻量、最常被跳过的一步,但它比重建索引更常解决问题。











