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列索引失效——这种细节容易被忽略,上线后慢查频发。
