JOIN字段类型或COLLATION不一致必然触发全表扫描,因隐式转换使索引失效;SHOW FULL COLUMNS比对Collation须一字不差,改字段定义和参数化查询才是有效解法。

为什么JOIN字段类型不一致必然触发全表扫描
不是“可能慢”,是MySQL优化器直接放弃索引——只要ON a.id = b.user_id两边类型不同(比如a.id是BIGINT,b.user_id是VARCHAR(20)),就会强制对其中一列做隐式转换。常见做法是把整列VARCHAR转成数字再比对,而函数作用于索引列,B+树就失效了。EXPLAIN里对应表的type一定是ALL,key为NULL,哪怕只有5万行也会卡住。
字符集或COLLATION不一致同样导致索引跳过
就算两边都是VARCHAR(32),只要COLLATION不同(比如utf8mb4_0900_as_cs vs utf8mb4_unicode_ci),MySQL仍会悄悄加CONVERT(... USING utf8mb4),执行计划照样降级。验证方法很简单:SHOW FULL COLUMNS FROM table_name LIKE 'field_name',比对Collation列是否**一字不差**。别信“都是utf8mb4就没事”,字符集相同但校对规则不同,一样崩。
临时加COLLATE或CAST在ON里根本没用
很多人试过写ON a.name = b.name COLLATE utf8mb4_0900_as_cs或者ON a.id = CAST(b.user_id AS SIGNED),语法能过,但索引依然不走。因为这是运行时转换,优化器无法下推,b.name或b.user_id上的原生索引完全被绕过。真正有效的只有改字段定义:ALTER TABLE b MODIFY user_id BIGINT,或统一CHARACTER SET和COLLATE后重建索引。
应用层传参不干净会让数据库白改
字段类型和字符集都对齐了,但代码里还是拼字符串:WHERE user_id = "123"(而字段是INT),MySQL照样隐式转。更糟的是输入带空格或字母,比如" 123 "或"123abc",可能截断、报错或匹配出错。必须用参数化查询,比如PreparedStatement显式指定SqlDbType.Int,API入口层还要校验输入是否为纯数字、无前后空格、长度合理。
最容易被忽略的是跨库场景:两个库的默认collation_connection可能不同,哪怕表结构一模一样,连上来那一刻字面量就被按错误规则解释了。上线前不查SELECT @@collation_connection,等于没做完。










