DATE()等函数导致索引失效,因MySQL无法在B+树中直接匹配函数结果;应改用范围查询,如create_time >= '2025-12-27' AND create_time < '2025-12-28'。

DATE()函数导致索引失效
只要在WHERE里对日期字段套DATE()、YEAR()、MONTH()这类函数,索引就直接作废。MySQL没法拿函数结果去B+树里查,只能把整列读出来挨个算——500万行表上这么干,12秒起步。
常见错误写法:WHERE DATE(create_time) = '2025-12-27'、WHERE YEAR(order_time) = 2023
- 把函数挪到右边:用范围代替函数,比如
create_time >= '2025-12-27' AND create_time - 如果必须按年/月查,提前建好生成列并加索引,例如:
ALTER TABLE orders ADD COLUMN create_year INT AS (YEAR(create_time)) STORED, ADD INDEX idx_create_year (create_year) - 别信“加了索引就万事大吉”,每次改SQL后一定要跑
EXPLAIN确认key字段非空、type不是ALL
隐式类型转换让索引“隐身”
日期字段是DATETIME或TIMESTAMP,但查询时传了个字符串没带时分秒,或者用了数字,MySQL会悄悄做类型转换,索引就失效了。
典型报错不明显,但EXPLAIN里能看到key为空、Extra出现Using where而不是Using index
- 确保传入值格式严格匹配字段定义:字段是
DATETIME,就传'2025-12-27 14:30:00',别只传'2025-12-27' - 避免用数字比较时间字段,比如
WHERE create_time = 1735286400(Unix时间戳)——这会触发隐式转换 - 用
SHOW CREATE TABLE确认字段类型,再对照检查应用层传参类型,尤其注意ORM框架是否自动做了格式化
LIKE模糊查时间字段?基本没戏
有人试过WHERE create_time LIKE '2025-12%'想走索引,结果发现还是全表扫。B+树索引依赖前缀有序性,而LIKE对时间字段本质是字符串匹配,优化器根本不会考虑走索引。
- 时间字段别用
LIKE,这是设计误用。真要按年月查,就用范围查询 - 如果业务强依赖“某年某月”的模糊入口,前端应拆成两个参数(
start_time和end_time),后端拼成范围条件 - 极少数场景需支持“输入年份自动补全”,可在应用层做预计算,查出年份列表缓存,不依赖数据库模糊匹配
统计信息过期也会让索引“装死”
表数据量突增(比如从10万涨到500万)、批量导入后没更新统计信息,MySQL优化器可能误判“走索引比全表扫描还慢”,主动放弃索引。
- 执行
ANALYZE TABLE orders强制刷新统计信息,特别是大表变更后 - 检查
information_schema.STATISTICS里的CARDINALITY是否合理,若为0或远低于实际唯一值数,说明统计失真 - 不要依赖自动分析,生产环境建议在ETL任务末尾加
ANALYZE TABLE步骤
DATE(),后者觉得“加了索引就一劳永逸”。但索引不是贴纸,它是活的,得配合查询写法、数据分布、优化器认知一起工作。


















