mysql中避免索引失效的常见原因与解决方法

来源:这里教程网 时间:2026-02-28 20:48:53 作者:

WHERE 条件中对索引列使用函数或运算

MySQL 无法使用索引加速

WHERE
子句中被函数包裹或参与运算的列,因为索引存储的是原始值,不是计算结果。

SELECT * FROM users WHERE YEAR(create_time) = 2023
create_time
索引失效;应改用范围查询:
create_time >= '2023-01-01' AND create_time 
WHERE age + 1 > 30
age
索引不走;改写为
age > 29
WHERE UPPER(name) = 'ALICE'
→ 建议在写入时统一大小写,或添加函数索引(MySQL 8.0+):
CREATE INDEX idx_name_upper ON users ((UPPER(name)))

LIKE 查询以通配符开头

LIKE
模式匹配中,前导
%
会强制全索引扫描或全表扫描,即使列上有索引。

WHERE name LIKE '%son'
→ 索引失效;若业务允许,优先使用后缀匹配:
name LIKE 'son%'
(可走索引)
需要前后模糊搜索时,考虑全文索引:
ALTER TABLE users ADD FULLTEXT(name)
,再用
MATCH(name) AGAINST('son' IN NATURAL LANGUAGE MODE)
短文本且查询频繁,可冗余生成拼音字段(如
name_pinyin
)并建索引,避免函数实时转换

隐式类型转换导致索引失效

WHERE
中索引列与条件值类型不一致,MySQL 会自动转换——若转换发生在索引列一侧,索引就失效。

user_id
INT
类型,但写成
WHERE user_id = '123'
→ 字符串常量触发隐式转整型,通常仍能走索引;但反过来:
WHERE user_id = CONCAT('1', '23')
WHERE user_id = CAST('123' AS CHAR)
就可能失效
更危险的是字符串字段存数字:如
phone VARCHAR(20)
建了索引,却执行
WHERE phone = 13812345678
→ MySQL 把索引列转为数字比较,索引失效
解决方法:确保参数类型与字段定义严格一致;用
EXPLAIN
验证
type
是否为
ref
range
,而非
ALL
index

联合索引未遵循最左前缀原则

联合索引

(a, b, c)
只有在查询条件包含
a
,或
a, b
,或
a, b, c
时才能高效使用;跳过左侧列会导致索引部分或完全失效。

WHERE b = 2 AND c = 3
→ 索引完全不走;必须带上
a
才行
WHERE a = 1 AND c = 3
→ 仅
a
部分生效,
c
无法利用索引(
b
是断点)
范围查询(
>
,
, <code>BETWEEN
,
LIKE 'xxx%'
)之后的列无法用索引:
WHERE a = 1 AND b > 2 AND c = 3
c
不走索引
高频查询字段尽量前置;必要时拆分索引,比如单独为
(b, c)
建索引,但需权衡写入开销
EXPLAIN SELECT * FROM orders WHERE status = 'paid' AND amount > 100 AND created_at > '2024-01-01';

如果

orders
上只有联合索引
(status, created_at, amount)
,这个查询实际只用到
status
created_at
因为是范围条件,后面的
amount
列索引失效——这种细节容易被忽略,上线后慢查频发。

相关推荐