📢 欢迎来到万事技术论坛!本站仅讨论合法编程技术话题,严禁外挂/作弊/黑产/盗版内容,违者封号。

精华MySQL 索引失效的 8 个典型场景(附验证方法)

dba_zhou 进阶会员

建了索引还全表扫,多半踩了下面某一条。每条都给出验证方式。

先记住验证手段——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
lin_dev 活跃会员

隐式类型转换那条最隐蔽,我们有个 user_id 字段是 varchar,ORM 传了 int 进去,慢查询查了半天才发现。现在建表统一用 bigint。

1楼 · 2026-09-28 13:21
captain_algo 活跃会员

请问 WHERE a=1 AND b>10 AND c=5 这种情况,把索引建成 (a, c, b) 会不会更好?

2楼 · 2026-09-28 13:21
dba_zhou 进阶会员

@captain_algo 会的。原则就是等值列在前、范围列在最后。不过也要看区分度和查询频率,实际开 EXPLAIN 对比一下最准。

3楼 · 2026-09-28 13:21
登录 后即可参与回复。