今天碰到一个慢sql的问题,sql明明按照最前缀的原则写的,但是索引就是不生效,最终排查发现是因为索引字段发生类型转换造成的。
一、表结构
1、表字段
2、表索引
二、问题sql
EXPLAIN
SELECT * FROM t_res
WHERE open = 1 AND res_date > CURRENT_DATE() AND res_date <= DATE_ADD( NOW(), INTERVAL 3 DAY) AND is_del = 1
GROUP BY dept_code
这个sql语句如果不出意外会使用open_date_index索引,然而执行sql计划确令人大失所望
通过sql计划可以看出,索引失效了,只是做了全表范围查询,那么这里会不会是mysql优化器优化了查询sql,我有尝试强制使用索引,
EXPLAIN
SELECT * FROM t_res FORCE INDEX(open_date_index)
WHERE open = 1 AND res_date > CURRENT_DATE() AND res_date <= DATE_ADD( NOW(), INTERVAL 3 DAY) AND is_del = 1
GROUP BY dept_code
再次执行计划,索引依然没有生效,到此可以很明确索引失效了;
三、解决索引失效
我仔细分析了下表结构,发现open和res_date字段是varchar类型的,而在sql查询的时候使用的类型不一致,其中open=1,会在查询的时候将数据库的open由字符类型转换为数值类型,res_date > CURRENT_DATE()会将res_date的字符类型转化日期类型,这中强制类型转换是索引的天敌,找到原因后,sql做下微调
EXPLAIN
SELECT*
FROMt_resFORCE INDEX(open_date_index)
WHEREopen = '1'AND res_date > DATE_FORMAT(CURRENT_DATE(),"%Y-%m-%d")AND res_date <=DATE_FORMAT(DATE_ADD(NOW(), INTERVAL 3 DAY),"%Y-%m-%d")AND is_del= '1'
GROUP BYdept_code
执行计划
这次 open_date_index索引生效,问题得到解决