mysql索引列参与函数计算会失效吗_mysql查询优化提示

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

MySQL 索引列用在函数里,索引真的会失效

直接说结论:是的,绝大多数情况下会失效。只要你在

WHERE
条件中对索引列施加了**非单调、不可下推的函数调用**,优化器就无法利用该索引做范围扫描或等值查找。

典型失效场景包括:

WHERE UPPER(name) = 'JOHN'
WHERE DATE(create_time) = '2024-01-01'
WHERE SUBSTRING(phone, 1, 3) = '138'
。这些写法会让 MySQL 被迫对每一行先计算函数结果再比对,彻底绕过索引。

例外情况极少:比如

WHERE col + 0 = 123
(隐式类型转换)或
WHERE col * 1 = 123
,某些版本可能仍能走索引,但完全不可依赖,也不建议这么写。

哪些函数操作可能“保索引”?要看是否支持索引下推和单调性

MySQL 5.7+ 支持部分函数的索引下推(ICP),但前提是函数本身可下推且不改变比较语义。目前真正安全可用的只有:

WHERE col LIKE 'abc%'
—— 前缀匹配,B+ 树天然支持
WHERE col IN ('a', 'b', 'c')
—— 多个等值,仍可走索引查找
WHERE col BETWEEN 10 AND 20
—— 范围查询,索引有效
WHERE col IS NULL
col IS NOT NULL
—— 对可空索引列也有效(需注意联合索引最左前缀规则)

YEAR(create_time) = 2024
这种看似简单,实际会触发全表扫描;而改写成
create_time >= '2024-01-01' AND create_time  才能命中索引。

EXPLAIN 看不到 key?别急着改 SQL,先确认执行计划细节

EXPLAIN
key
NULL
是索引失效的强信号,但不是唯一依据。更关键要看:

type
是否为
ALL
index
(全表/全索引扫描)
rows
是否远大于实际匹配数(说明没剪枝)
Extra
是否出现
Using where; Using index
(好) vs
Using where
(坏,回表+无索引过滤)

有时索引“看似没被选中”,其实是优化器基于统计信息判断走全表更快(比如表小、条件选择率高)。这时

FORCE INDEX
可验证,但不推荐线上滥用。

替代方案:函数索引(MySQL 8.0.13+)和生成列是正解

如果业务真绕不开函数逻辑,优先考虑:

创建函数索引:
CREATE INDEX idx_name_upper ON users ((UPPER(name)))
—— 注意双括号语法,只在 MySQL 8.0.13+ 支持
用生成列 + 普通索引:
ALTER TABLE users ADD name_upper VARCHAR(64) GENERATED ALWAYS AS (UPPER(name)) STORED;</code><br><code>CREATE INDEX idx_name_upper ON users (name_upper);
应用层预计算并存入普通字段(如
name_lower
),索引、查询、更新都更可控

函数索引对

JSON
字段提取、时间截断等场景特别有用,但要注意它不支持全文索引、空间索引,且维护成本略高。

最常被忽略的一点:即使用了函数索引,

WHERE UPPER(name) = ?
能走,但
WHERE LOWER(name) = ?
依然不能——函数索引只对定义时的表达式生效,不泛化。

相关推荐