索引失效是核心问题,因函数运算使数据库无法利用B+树索引,导致全表扫描;应将函数移至常量侧或改用范围查询,函数索引仅作补充。

因为这会让数据库无法有效使用索引,导致全表扫描,性能急剧下降。
索引失效是核心问题
数据库的B+树索引是按列的原始值有序存储的。一旦在 WHERE 中对列使用函数(比如 WHERE YEAR(create_time) = 2023 或 WHERE UPPER(name) = 'ABC'),优化器就无法直接拿函数结果去匹配索引中的原始值。它必须先对每一行计算函数,再比对——相当于绕过了索引,只能逐行扫描。
常见触发函数运算的写法
- 日期截取类:YEAR()、MONTH()、DATE()、DATE_FORMAT()、TO_DAYS()
- 字符串处理类:UPPER()、LOWER()、TRIM()、SUBSTRING()、CONCAT()
- 数学/类型转换类:ABS()、ROUND()、CAST()、CONVERT()
更高效的替代方案
把函数从列上“移开”,改到常量侧或用范围表达:
- ❌ WHERE YEAR(create_time) = 2023 ✅ 改为:WHERE create_time >= '2023-01-01' AND create_time
- ❌ WHERE UPPER(name) = 'JOHN' ✅ 改为:WHERE name = 'john'(配合大小写敏感校对规则),或建函数索引(MySQL 8.0+/PostgreSQL支持)
- ❌ WHERE price * 1.1 > 100 ✅ 改为:WHERE price > 100 / 1.1
特殊情况:函数索引可解但需谨慎
MySQL 8.0、PostgreSQL、Oracle 等支持函数索引(如 CREATE INDEX idx_year ON t (YEAR(create_time))),但它只对完全匹配该函数的查询生效,且会增加维护成本和存储开销。优先考虑重写条件,函数索引应作为补充手段而非默认方案。










