字符集或排序规则不一致会导致JOIN索引失效,因B+树依赖严格有序比较,collation差异使相同字符串判定不等,优化器无法保证结果正确性,被迫全表扫描;需用SHOW CREATE TABLE或information_schema对比并统一CHARACTER SET与COLLATION。

为什么字符集不一致会让 JOIN 索引失效
MySQL 在做 JOIN 时,如果关联字段的字符集(charset)或排序规则(collation)不同,优化器会拒绝使用索引——不是“不想用”,而是“不能用”。因为 B+ 树索引依赖严格有序比较,而不同 collation 下,相同字符串可能被判定为不等(比如 utf8mb4_unicode_ci 和 utf8mb4_general_ci 对某些 emoji 或德语变音符号的排序逻辑不同),数据库无法保证索引扫描结果的正确性,只能退化为全表扫描或临时转换字段值(隐式 cast),导致 key 列在 EXPLAIN 中显示为 NULL。
如何快速定位是字符集/排序规则惹的祸
执行 EXPLAIN 后观察 possible_keys 有值但 key 为 NULL,且关联字段类型都是 VARCHAR / TEXT 类型时,优先检查两端字段的定义:
- 用
SHOW CREATE TABLE table_name查看两个表中参与JOIN的列,对比CHARACTER SET和COLLATION - 直接查
information_schema.COLUMNS:SELECT column_name, character_set_name, collation_name FROM information_schema.COLUMNS WHERE table_name IN ('tb_mdm_verification_rules_result', 'tb_unqualify_sc_pool') AND column_name IN ('project_code', 'customer_id'); - 特别注意:即使字符集相同(如都是
utf8mb4),只要collation不同(如utf8mb4_0900_as_csvsutf8mb4_unicode_ci),照样失效
统一 collation 的实操步骤(不改数据)
目标是让关联字段的 collation 完全一致,且推荐使用 MySQL 5.7+ 默认兼容性最好的组合:utf8mb4 + utf8mb4_unicode_ci(或更严格的 utf8mb4_0900_as_cs,但需确认业务是否允许大小写/重音敏感):
- 先确认当前字段定义:
SHOW FULL COLUMNS FROM sunacwy_mdm.tb_mdm_verification_rules_result LIKE 'project_code'; - 修改单个字段的
collation(不影响已有数据):ALTER TABLE sunacwy_mdm.tb_mdm_verification_rules_result MODIFY project_code VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 批量修改多个字段(建议分步,避免锁表太久):
ALTER TABLE tb_unqualify_sc_pool MODIFY project_code VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY mdm_data_id VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 注意:如果字段上有索引,
MODIFY会自动重建索引;若字段是主键或外键,需先删约束再加回
容易被忽略的坑:连接字符串字面量和隐式转换
就算表字段统一了,SQL 里硬编码的字符串也可能触发隐式转换:
- 错误写法:
ON t1.project_code = t2.project_code AND t1.customer_id = 'abc123'—— 如果t1.customer_id是utf8mb4_bin,而字面量默认用连接字符集(常为utf8mb4_general_ci),仍可能失效 - 安全写法:显式声明字面量 collation:
t1.customer_id = _utf8mb4'abc123' COLLATE utf8mb4_unicode_ci - 更稳妥的方式:在应用层确保传入参数的编码与字段完全一致,避免 JDBC 连接串里漏配
useUnicode=true&characterEncoding=utf8mb4 - 额外提醒:视图、函数、存储过程内部引用的字段,其 collation 继承自底层表,但若涉及字符串拼接或常量,同样要检查


















