Tips: MySQL在执行条件判断时,若参数类型与字段类型不匹配, 则会作类型转换, 符合转换规则的, 转换完成后可以利用索引

    而当参数为字符串,字段类型为整型时, 这个转换是成立的, 比如这个case.

    因此我们有必要查一下是什么原因.

    在优化器执行流程中, 要选择索引, 需要先判断where的部分的条件操作能否使用索引.经典的有,

    Tips: 在字段上作函数操作,是无法使用索引的. 比如 where c+1 = 10

    因此怀疑是在判断过程出了什么岔子.

    调用栈

    然后我们发现了这样一段代码, MySQL · 最佳实践 · 一个“异常”的索引选择 - 图1

    简单说,就是在IN的入口有一个判断, 如果in中的字段类型不兼容, 则认为不可使用索引. 而这个arg_types_compatible 的赋值逻辑是: 也就是说,当IN列表中出现超过一个字段类型时, 就认为类型不兼容.

    这个本来是一个优化操作, 提前判断避免额外的后续判断.

    至此,我们就清楚, 问题来自于IN和列表中的类型问题. 以下几个对照试验可以作为验证:

    如果把他当作bug处理,只需要在get_func_mm_tree函数中去掉上述最后一个图中的判断逻辑即可, 有兴趣的读者可以自己注释后验证.

    翻了代码发现果然是去掉了这个判断.

    但有趣的是, 官方并不是为了解决这个问题而作的修改, 实际上是在支持(a,b) in (X, Y)这样的语法时,由于这个语句就不能要求XY必须相同类型,因此去掉了这个判断, “阴差阳错”把这个问题改过来了.

    翻了下commit log, 发现在5.7.3修复的, 因5.7.3之后,文章开头的这个例子的优化器结果就变了.

    所以我们看到, 实际上即使是小版本, 也是可能改变程序行为的.

    而版本更新,尤其是要使用官方最新版本的特性, 有时候是必须作程序升级的.

    而即使是小版本号的不同, 也可能对业务造成影响.

    上述这个需求和现状,其实是有矛盾的, 运维的同学们可以考虑下, 如何处理这种潜在风险呢?