隐式转换导致索引失效,因mysql对varchar列逐行执行cast操作,破坏b+树有序性,优化器被迫全表扫描,explain显示key=null、type=all;int列传字符串虽常能走索引,但存在溢出或截断风险。

因为隐式转换让 MySQL 必须对索引列逐行做 CAST/CONVERT,破坏 B+ 树的有序性前提,优化器只能放弃索引走全表扫描。
WHERE varchar_col = 123 为什么 key=NULL
当 varchar_col 是字符串类型,而条件写成 WHERE varchar_col = 123(不加引号),MySQL 会把每一行的 varchar_col 值都转成浮点数再比对,等价于 WHERE CAST(varchar_col AS DOUBLE) = 123。
- 这个
CAST是作用在列上的函数操作,B+ 树无法跳过分支做二分查找 -
EXPLAIN中type显示ALL,key为NULL,rows等于表总行数 - 哪怕只查 1 行,逻辑上也等价于全表扫描;数据量一上来,响应时间从毫秒级变成秒级
- MyBatis 用
${id}拼接、前端传参未校验、日志脚本硬编码数字常量,都极易触发
WHERE int_col = '123' 看似安全但有隐患
反向情况——int_col 是整型,条件写成 WHERE int_col = '123',多数时候仍能走索引,但风险藏在细节里:
- MySQL 通常把字符串字面量转成整数,这个转换发生在优化器阶段,不破坏索引路径
- 但若字符串含非数字字符(如
'123abc')或超长(如'99999999999999999999'),可能溢出为 0 或截断,导致查不到数据 -
EXPLAIN看起来正常(key有值、rows小),但结果错,问题更难定位 - ORM 参数绑定时,Java
Integer传给varchar字段,JDBC 驱动不报错,SQL 执行时已悄悄转换
联合索引最左列一隐式转换,整个前缀就废了
比如联合索引 KEY idx_code_age_name (code, age, name),其中 code 是 VARCHAR,但查询写成 WHERE code = 101 AND age = 21:
-
code = 101触发隐式转换,code列无法利用索引排序,最左前缀失效 - 后续
age和name即使类型匹配,也无法享受“索引下推”(ICP)优化 - 实际执行可能退化为只用
age单列索引(如果存在),或干脆全表扫 - 这种失效不体现在
key为空,而是key_len明显偏小、ref为const但rows异常大
真正容易被忽略的是:它不报错、不告警,SQL 语法完全合法,数据量小时看不出问题。等线上表涨到千万级、QPS 上升,慢查询才突然爆发——而你翻日志看到的 SQL,和开发环境跑的那条,看起来一模一样。











