type=ALL 确定未走索引,主因包括函数操作、隐式类型转换、联合索引顺序错位、字段参与计算;需用SHOW INDEX和INFORMATION_SCHEMA确认索引真实状态及可见性。

EXPLAIN 显示 type=ALL 就是全表扫描,得立刻查原因
MySQL 没走索引最直观的信号就是 EXPLAIN 输出里 type 列是 ALL。这不是“可能没走索引”,是确定没走——哪怕表上有索引,也可能因为条件写法、数据类型不匹配或隐式转换被跳过。
常见诱因包括:
-
WHERE子句对索引字段用了函数,比如WHERE YEAR(created_at) = 2024,created_at上有索引也无效 - 字符串字段用数字比较:
WHERE status = 1,而status是VARCHAR类型,触发隐式转换 - 联合索引顺序错位:索引是
(a, b, c),但查询只用了b或c,前面字段没出现在WHERE中,就无法命中 - 索引字段参与了计算:
WHERE price * 1.1 > 100,直接放弃索引
用 SHOW INDEX 和 INFORMATION_SCHEMA 查索引真实状态
别光看建表语句里有没有 INDEX 关键字——索引可能被禁用、损坏,或者根本没建在目标列上。先确认它是不是真的存在且可用。
执行这两条命令:
SHOW INDEX FROM orders;
看 Key_name、Seq_in_index(顺序)、Cardinality(基数)。如果 Cardinality 是 1 或接近总行数,说明索引区分度极差,基本等于没用。
再查是否被意外禁用:
SELECT index_name, is_visible FROM information_schema.statistics WHERE table_name = 'orders' AND table_schema = 'your_db';
is_visible 为 NO 表示索引存在但 MySQL 不会考虑它——可能是人为 ALTER TABLE ... INVISIBLE 过,也可能是升级后默认行为变化。
ORDER BY + LIMIT 组合常绕过索引,尤其带 JOIN 时
很多人以为加了索引就能加速分页,但 ORDER BY created_at DESC LIMIT 20 在大表上仍可能慢,特别是当 created_at 索引选择性低(比如大量相同值),或者 WHERE 条件没覆盖到排序字段的前缀。
更隐蔽的问题是 JOIN 后再 ORDER BY:即使驱动表走了索引,被驱动表的排序字段若不在联合索引里,MySQL 可能放弃索引,改用 filesort。
实操建议:
- 把
WHERE条件字段和ORDER BY字段一起放进联合索引,顺序按“等值条件 → 范围条件 → 排序字段”排列,例如(status, created_at)对应WHERE status = 'paid' ORDER BY created_at DESC - 避免在 JOIN 结果集上排序;优先让被驱动表的关联字段+排序字段组成覆盖索引
- 用
EXPLAIN FORMAT=JSON看using_filesort是否出现,出现就说明排序没走索引
索引不是越多越好,冗余和重复索引会拖慢写入和优化器决策
一个表上有 (a)、(a,b)、(a,b,c) 三个索引?大概率只需要保留 (a,b,c)。MySQL 优化器面对多个可选索引时,要花时间评估成本,字段多、索引多,反而容易选错执行计划。
检查冗余索引的简单方法:
SELECT s1.table_name, s1.index_name AS idx1, s2.index_name AS idx2 FROM information_schema.statistics s1 JOIN information_schema.statistics s2 ON s1.table_schema = s2.table_schema AND s1.table_name = s2.table_name AND s1.seq_in_index = 1 AND s2.seq_in_index = 1 AND s1.column_name = s2.column_name WHERE s1.index_name != s2.index_name AND s1.index_name NOT LIKE 'PRIMARY';
真正影响命中率的,往往是那几个关键查询路径上的索引质量,而不是总数。删掉 ALTER TABLE t DROP INDEX idx_old 前,务必用 EXPLAIN 验证所有依赖它的查询是否还能走其他有效索引。
复杂点在于:有些索引看起来冗余,但在不同查询条件下承担不同角色——比如一个索引支持等值查询,另一个支持范围+排序。不能只看字段前缀重叠就删。










