加了索引仍全表扫描,主因是查询未满足最左前缀、like前置通配、索引列用函数或隐式类型转换;需用explain看type(非all)和key(非null)确认走索引;高区分度、高频过滤/排序字段优先建索引,联合索引按过滤性强+频率高排序;覆盖索引可避免回表,但要求select字段全在索引中。

为什么加了索引还是全表扫描?
MySQL 并不总是用索引,即使字段上有索引。常见原因是查询条件未触发索引的最左前缀匹配,比如对 name 建了联合索引 (name, age),但查询写成 WHERE age = 25,这时索引完全失效。另外,LIKE 以通配符开头(如 LIKE '%abc')、在索引列上使用函数(如 WHERE UPPER(name) = 'ABC')或隐式类型转换(如字符串字段传入数字)都会导致索引失效。
如何确认某条 SQL 是否走了索引?
必须用 EXPLAIN 看执行计划,重点关注 type 和 key 字段:type 是 ref、range 或 const 表示走了索引;key 显示实际使用的索引名;若 key 为 NULL 或 type 是 ALL,就是全表扫描。
示例:
EXPLAIN SELECT * FROM users WHERE email = 'a@b.com';
如果 email 有索引且查询无干扰操作,type 应为 ref,key 显示索引名。
哪些字段适合建索引?
不是所有字段都该加索引。优先考虑:
- WHERE、JOIN、ORDER BY、GROUP BY 中高频出现的列
- 区分度高的列(如
user_id比gender更适合单列索引) - 联合索引按「过滤性强 + 查询频率高」的顺序排列,例如常查
WHERE status = ? AND created_at > ?,且status取值少,created_at区分度高,则应建(created_at, status)而非反过来 - 避免在频繁更新的字段上建过多索引,会拖慢写入性能
覆盖索引能彻底避免回表吗?
可以,但前提是 SELECT 的所有字段都在索引中。比如表有 id、name、email,建了联合索引 (email, name),那么 SELECT name, email FROM users WHERE email = 'x' 就是覆盖索引查询,Extra 显示 Using index,无需回主键索引查数据行。
但如果写成 SELECT * 或包含 id(不在索引里),就会回表——这是最容易被忽略的性能损耗点。
真正要减少扫描,核心不是“有没有索引”,而是“查询是否能只靠索引完成”。










