函数运算使索引失效,因B+树存储原始值而无法匹配计算结果;应将函数移至常量侧,如DATE(log_time)='2026-11-05'改为log_time>='2026-11-05' AND log_time

函数运算让索引值“认不出来”
MySQL 的 B+ 树索引是按字段原始值排序存储的,比如 created_at 列存的是 '2026-11-05 03:45:00' 这样的完整时间戳。一旦写成 YEAR(created_at) = 2026,优化器就无法直接在索引里找“年份为 2026”的节点——因为索引里根本没有“2026”这个值,只有带时分秒的完整时间。
EXPLAIN 里 key 为 NULL 就是铁证
执行 EXPLAIN SELECT * FROM logs WHERE DATE(log_time) = '2026-11-05'; 后,如果 key 字段显示 NULL,说明优化器压根没考虑用索引;type 是 ALL 更是确认全表扫描。这不是配置问题,也不是索引没建好,而是查询写法本身切断了索引匹配路径。
改写必须把计算挪到常量侧
不能依赖数据库“聪明”,得主动帮它对齐索引结构:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
-
WHERE DATE(log_time) = '2026-11-05'→ 改成WHERE log_time >= '2026-11-05' AND log_time -
WHERE UPPER(name) = 'JOHN'→ 改成WHERE name = 'john'(并确保业务存小写)或建函数索引(MySQL 8.0+):CREATE INDEX idx_name_upper ON users ((UPPER(name))) -
WHERE price * 1.1 > 100→ 改成WHERE price > 100 / 1.1,保持price是裸列
别信“小表无所谓”,隐式成本藏得深
即使表只有几万行,函数运算也会阻止索引下推(Using index condition 消失),导致更多数据页被读入内存;更麻烦的是,这类 SQL 在 ORM 自动生成、日志埋点、监控告警脚本里高频出现,容易批量引发慢查。真正要警惕的不是单条语句多慢,而是它会掩盖真实瓶颈——你以为缺的是索引,其实缺的是写法约束。










