MySQL性能优化(三)函数运算导致无法使用索引
有时侯我们会遇到这样的情况:明明字段上已经建立了索引,但是查询还是无法使用索引。
其中有一种情况是因为SQL中对索引字段进行了运算。
一个例子
select * from user where date(gmt_modified) = date(now())
执行计划
从执行计划可以看到,possible_keys是空的,没有任何索引可用。但实际上gmt_modified上是有索引的。
因为where条件对gmt_modified做了函数运算,导致无法使用索引。
改写SQL
这种情况下,我们可以对SQL进行改写,避免在索引子弹上使用函数,同时保持SQL的逻辑不变。
对于这个案例中的SQL,我们可以这么改写:
select * from user where gmt_modified >= date(now()) and gmt_modified < date(date_add(now(), interval 1 day))
这2个SQL的逻辑一样,都是获取修改时间为当天的用户信息。改写之后,我们再来看执行计划:
可以看到,改写后,SQL用到了idx_gmt_modified索引。扫描的记录数为3119。而之前全表扫描需要访问2.8万行数据。
总结
索引子弹上的函数运算还会以其他形式出现,如:
select * from t1 where b+0 = 0; select * from t1 where cc||'' = ''
除了对索引字段进行显式的运算,还存在另外一种更隐蔽的情况:字段类型隐式转换。
关于字段类型隐式转换的例子,我们在后续的文章中介绍。