MySQL我们知道,如果对索引字段进行函数操作,可能会破坏索引值的顺序,因此优化器决定放弃树搜索功能。隐式类型转换也会导致树搜索被放弃。因为类型转换相当于在条件字段上使用函数。例如:假设tradeid字段有一个索引,并且是varchar类型:mysql>select*fromtradelogwheretradeid=110717;相当于:mysql>select*fromtradelogwhereCAST(tradidASsignedint)=110717;我们来看一个隐式字符编码转换导致的慢SQL::业务中有一个SQL执行耗时1.31秒:看执行计划:从执行计划分析可以看出问题在于r表,即h_merge_result_new_indicator表扫描全表,检查表是否有联合索引。但是联合索引的范围会失效,所以我打算新建一个联合索引:检查预先创建的联合索引的字段选择性:结合选择性:createindexidx_hmrnionh_merge_result_new_indicator(keyName,module,BATCH_NO);创建完成后,再次查看执行方案依旧无效:查看表结构:另外3个表结构中有2个utf8mb4和1个utf8:字符集utf8mb4是utf8的超集,所以当这两种类型的字符串是比较,MySQL内部的操作是:先将utf8字符串转为utf8mb4字符集,然后再进行比较。因此:这部分会被转化,然后关联到h_merge_result_new_indicator。优化只需要将字符集编码转成utf8再关联h_merge_result_new_indicator就可以使用索引了:看查询只用了0.02秒:但是还是有问题,上面的执行计划key_len是606=(100*3+3)+(100*3+3)也就是说没有使用BATCH_NO字段上的索引。我们知道索引少了一个字段,占用会减少,不会太臃肿。因此联合索引只需要包含r(keyName,module):dropindexidx_hmrnionh_merge_result_new_indicator;在h_merge_result_new_indicator(keyName,module)上创建索引idx_hmrni;结论对索引字段进行函数式操作可能会破坏索引值的顺序,因此优化器决定放弃树搜索功能。本例为隐式字符编码转换,与在其他条件索引上使用函数相同,因为需要对索引字段进行函数操作,导致全索引扫描。MySQL的优化器确实有“偷懒”之嫌。即使简单的将whereid+1=1000改写为whereid=1000-1可以利用索引快速查找,也不会主动改写这条语句。保证索引值的顺序在条件索引上不被破坏,是优化索引的利器。
