建了索引还全表扫,多半踩了下面某一条。每条都给出验证方式。
先记住验证手段——EXPLAIN 看 type 列:
| type | 含义 |
|---|---|
system/const |
最好,主键或唯一索引命中一行 |
ref/range |
正常,用到索引 |
index |
扫全索引(比全表好点) |
ALL |
全表扫描,要优化 |
1. 隐式类型转换
-- phone 是 varchar,却用数字查:索引失效
SELECT * FROM user WHERE phone = 13800138000;
-- 正确
SELECT * FROM user WHERE phone = '13800138000';
MySQL 会对列做类型转换,等于在列上加函数。
2. 对索引列用函数
WHERE DATE(created_at) = '2026-09-28' -- 失效
WHERE created_at >= '2026-09-28' AND created_at < '2026-09-29' -- 生效
3. 最左前缀没用上
联合索引 (a, b, c),条件必须从 a 开始且连续:
WHERE a=1 AND b=2 -- 用到 a,b
WHERE b=2 AND c=3 -- 跳过 a,索引基本白建
WHERE a=1 AND c=3 -- 只用到 a,c 用不上
4. 范围条件右边的列失效
WHERE a=1 AND b>10 AND c=5:索引用到 a 和 b,c 因为 b 是范围查询而失效。建索引时把范围列放最后。
5. 前导模糊查询
WHERE name LIKE '%abc' -- 失效
WHERE name LIKE 'abc%' -- 生效
真要全文搜索上 FULLTEXT 或 ES。
6. OR 连接的非索引列
WHERE id = 1 OR name = 'x' -- 若 name 无索引,整个走全表
拆成两个查询用 UNION,或给 name 也建索引。
7. 不满足回表成本阈值
要查的行太多(经验值超过全表 30%)时,优化器会放弃索引直接全表扫——因为回表次数太多反而更慢。这是优化器的正确选择,别硬改。
8. 统计信息过期
ANALYZE TABLE user; -- 大批量导入后跑一次
排查顺序:
EXPLAIN→ 看type和key→ 对照上面 8 条 → 改完再EXPLAIN确认。别凭感觉调索引,实测最靠谱。
楼主 · 2026-09-28 13:21 · 浏览 8

