因为date()函数调用阻断索引下推,mysql需回表逐行计算,导致实际扫描行数远超返回行数;应改用范围查询:where create_time >= '2024-01-01 00:00:00' and create_time
WHERE子句里用DATE()为什么EXPLAIN显示走索引却还是慢
因为函数调用阻断了索引下推(Index Condition Pushdown),MySQL必须先读取整行数据,再对
create_time字段执行DATE()计算,无法在存储引擎层直接过滤。即使EXPLAIN显示type=range、key有值,实际仍是“索引扫描+逐行计算”,Rows_examined远高于Rows_sent。实操建议:
- 把
WHERE DATE(create_time) = '2024-01-01'改成WHERE create_time >= '2024-01-01 00:00:00' AND create_time- 如果业务强依赖日期维度,可添加生成列:
ALTER TABLE t ADD COLUMN create_date DATE AS (DATE(create_time)) STORED,再对create_date建索引- 避免在WHERE中对任何索引列使用函数——包括
YEAR()、MONTH()、JSON_EXTRACT()等DETERMINISTIC函数真能提升性能吗
能,但只在特定场景下起作用:MySQL优化器会缓存确定性函数的计算结果(尤其在排序、分组、临时表构建阶段),且允许将其用于函数索引(MySQL 8.0.13+)。但前提是函数声明为
DETERMINISTIC,且内部不调用NOW()、RAND()、UUID()等非确定性函数。常见陷阱:
- 自定义函数(UDF)默认被视为
NOT DETERMINISTIC,即使逻辑上是确定的;必须显式声明DETERMINISTIC关键字DETERMINISTIC不等于“快”——它只是告诉优化器“结果可复用”,若函数本身含循环、IO或复杂正则,仍会拖慢查询- 函数索引要求列值稳定,若底层字段频繁更新,函数索引维护成本会上升
哪些内置函数可以安全标为DETERMINISTIC
MySQL内置函数大部分已是确定性的,但需注意边界情况:
LOWER()、UPPER()、TRIM()、SUBSTRING()、CONCAT()(不含UUID()等)——可放心用于函数索引JSON_EXTRACT()是确定性的,但性能差;不如提前抽取到生成列并建索引MD5()、SHA2()虽确定,但CPU开销大,批量计算时慎用;建议写入时预计算并存入冗余字段IF()、CASE WHEN表达式整体是否确定,取决于各分支内所有子表达式是否都确定怎么验证函数是否被真正缓存或下推
不能只看
EXPLAIN,得查运行时行为:
- 启用
performance_schema后,查events_statements_history_long,过滤SQL文本含函数名,观察TIMER_WAIT中函数计算占比- 对比两组查询耗时:
SELECT COUNT(*) FROM t WHERE f(col) = 'x'vsSELECT COUNT(*) FROM t WHERE col = 'y'(已知映射关系),差值即函数开销基线- 对函数索引执行
SHOW INDEX FROM t,确认Comment列为functional index,且Key_name非空函数是否被优化器信任,关键不在声明,而在它是否真的没副作用——哪怕只在函数体里多写一行
SELECT 1;,也会让MySQL降级为NOT DETERMINISTIC。












