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

1次阅读

mysql中对索引列使用函数(如upper、date)会导致索引失效,因b+树基于原始值排序;应改用范围查询或mysql 8.0+函数索引,并通过explain的key和type字段确认。

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

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 输出中的 keytype 字段。若 keyNULLtypeALL,基本可确认索引未被使用。

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' 就能命中该索引
  • 注意:函数索引只支持确定性函数(如 LOWERTRIM),不支持 NOW()RAND()

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

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

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

这类问题往往比明面上的函数更难察觉,排查时要连带检查 SHOW CREATE tableEXPLAIN format=TRADITIONALExtra 提示(如出现 using where; Using index 是好的,Using filesortUsing temporary 则需警惕)。

text=ZqhQzanResources