函数操作使索引失效,因索引仅存原始值;应将计算移至常量侧,保持索引列原始形式在比较左侧,如where date(create_time)='2024-01-01'改为where create_time>='2024-01-01'and create_time

函数操作破坏索引的有序结构
索引(如 B+ 树)存储的是字段的原始值,并按这些值严格排序。一旦在 WHERE 中对索引列套用函数(如 UPPER()、DATE()、YEAR()),数据库就无法直接拿函数结果去比对索引项——因为索引里根本没有 UPPER(name) 的值,只有原始的 name。
它只能退回到“逐行取值 → 执行函数 → 判断条件”这个流程,也就是全表扫描。
常见函数失效写法与等价改法
核心原则:把计算/转换移到常量侧,保持索引列以原始形式出现在比较左侧。
-
WHERE DATE(create_time) = '2024-01-01'→ 改为WHERE create_time >= '2024-01-01' AND create_time -
WHERE YEAR(created_at) = 2022→ 改为WHERE created_at >= '2022-01-01' AND created_at -
WHERE UPPER(name) = 'ALICE'→ 改为WHERE name = 'alice'(若业务允许大小写敏感),或建函数索引(MySQL 8.0+ / PostgreSQL):CREATE INDEX idx_name_upper ON users (UPPER(name))
为什么不能依赖“数据库自动优化”?
有些旧版 MySQL 在特定场景下(如 id = '123',id 是 INT)看似还能走索引,但这只是隐式转换的兼容行为,不是设计保障。PostgreSQL、Oracle 等更严格,一有函数就放弃索引。
更关键的是:即使能走,也可能因统计信息不准或执行计划缓存导致不稳定。真实线上环境里,靠“有时候能走”不如靠“明确不碰函数”。
函数索引不是万能解药
MySQL 8.0+ 和 PostgreSQL 支持函数索引,但要注意:
- 写入性能下降:每次插入/更新都要多算一次函数值并维护索引项
- 索引体积增大:函数结果可能比原字段更长(比如
REVERSE(long_text)) - 可维护性差:业务逻辑分散到 DDL 层,后续修改函数需重建索引
- 不是所有函数都支持:MySQL 对
JSON_EXTRACT等复杂表达式仍有约束
真正该优先做的,是让查询适配索引,而不是反过来让索引迁就查询写法。










