mysql函数对索引使用有影响吗_mysql查询性能分析

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

MySQL 函数会破坏索引的使用

只要在

WHERE
子句中对索引列施加函数(如
UPPER()
DATE()
SUBSTRING()
YEAR()
),MySQL 通常无法走该列上的索引,即使索引存在且匹配查询条件。本质原因是:索引是按原始列值有序存储的,而函数改变了值的形态或范围,优化器无法直接定位 B+ 树中的位置。

SELECT * FROM users WHERE UPPER(name) = 'JOHN'
→ 即使
name
有索引,也会全表扫描
SELECT * FROM orders WHERE DATE(created_at) = '2024-01-01'
created_at
索引失效,应改用范围查询
例外:MySQL 8.0+ 对部分函数(如
JSON_EXTRACT()
配合生成列)支持函数索引,但需显式创建

如何判断函数是否导致索引失效

核心方法是看

EXPLAIN
输出中的
key
type
字段。若
key
NULL
type
ALL
,基本可确认索引未被使用。

EXPLAIN SELECT * FROM logs WHERE YEAR(log_time) = 2024;

对比优化后的写法:

EXPLAIN SELECT * FROM logs WHERE log_time >= '2024-01-01' AND log_time < '2025-01-01';
前者
key: NULL
,后者
key
显示实际使用的索引名
注意:即使函数出现在
SELECT
列表(如
SELECT UPPER(name)
),只要
WHERE
里没动索引列,不影响索引选择

函数索引(MySQL 8.0+)是绕过限制的可行方案

当业务逻辑强依赖函数查询(如大小写不敏感匹配、日期截断),又不能改应用层时,可建函数索引。它把函数计算结果持久化为虚拟列并索引,代价是额外存储和维护开销。

必须用
PERSISTENT
虚拟列 + 普通索引,或直接用 MySQL 8.0 的函数索引语法
示例:让
email
字段忽略大小写查询
CREATE INDEX idx_email_lower ON users ((LOWER(email)));
之后
WHERE LOWER(email) = 'a@b.com'
就能命中该索引
注意:函数索引只支持确定性函数(如
LOWER
TRIM
),不支持
NOW()
RAND()

常见“看似没函数,实则隐含函数调用”的场景

有些写法表面没显式函数,但 MySQL 内部做了类型转换或隐式处理,同样导致索引失效。

字符串字段存数字(如
status VARCHAR(10)
),却写
WHERE status = 1
→ 触发隐式类型转换,索引失效
字符集/排序规则不一致:
utf8mb4_0900_as_cs
列与
utf8mb4_general_ci
常量比较,可能放弃索引
使用
LIKE '%abc'
开头通配符,本质等价于
SUBSTRING(col, ...)
,B+ 树无法跳查

这类问题往往比明面上的函数更难察觉,排查时要连带检查

SHOW CREATE TABLE
EXPLAIN FORMAT=TRADITIONAL
Extra
提示(如出现
Using where; Using index
是好的,
Using filesort
Using temporary
则需警惕)。

相关推荐