EXPLAIN中key为NULL且type为ALL是字符集或排序规则不一致的直接证据;需比对左表字段、右表字段及连接层三处collation,统一为完全相同的utf8mb4_0900_as_cs等,并用ALTER TABLE MODIFY同时指定CHARACTER SET与COLLATE修正。

EXPLAIN里key=NULL就是字符集不一致的直接证据
看到EXPLAIN输出中key为NULL、type是ALL或index,且关联字段明明建了索引——这基本不是SQL写法问题,而是MySQL在JOIN前发现两边字段的CHARACTER SET或COLLATION不一致,主动弃用索引。它不是“懒得用”,而是“不敢用”:B+树索引依赖严格有序比较,而不同collation下,相同字符串可能被判定为不等(比如utf8mb4_unicode_ci和utf8mb4_0900_as_cs对德语ä的排序逻辑不同),优化器无法保证扫描结果正确性,只能退化为全表扫描或临时转换字段值。
查哪三层collation才能准确定位问题
别只看表结构注释或Java实体类,得实打实查数据库里的三处collation是否完全一致:
-
SHOW FULL COLUMNS FROM table1 LIKE 'join_col'—— 查左表字段的Collation列 -
SHOW FULL COLUMNS FROM table2 LIKE 'join_col'—— 查右表字段的Collation列 -
SELECT @@collation_connection—— 查当前连接默认规则,它还会影响SQL中字面量(如'abc')的隐含collation
只要任意一对不完全相同(例如utf8mb4_unicode_ci vs utf8mb4_0900_as_cs),就可能触发隐式CONVERT(USING ...),导致索引跳过。
ALTER TABLE改字符集必须同时指定CHARACTER SET和COLLATE
只写ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4是无效的——它不会改已有字段的COLLATE,大概率保留旧值(比如utf8mb4_general_ci)。真正生效的写法是:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
ALTER TABLE table2 MODIFY join_col VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs;
漏掉CHARACTER SET或COLLATE任一者,修改后SHOW CREATE TABLE里都看不到二者同时出现,索引失效问题依旧存在。大表操作会锁表重建索引,MySQL 8.0+若满足条件可加ALGORITHM=INPLACE,但务必先在测试环境验证。
为什么临时用CONVERT()或COLLATE强制转只是换种方式慢
有人试过在ON里写ON a.name = CONVERT(b.name USING utf8mb4)或ON a.name = b.name COLLATE utf8mb4_unicode_ci,看似“绕过”了问题,实际执行计划里会出现Using where; Using join buffer,说明转换发生在逐行过滤阶段,不是索引查找阶段。CPU开销从磁盘IO转移到了内存计算,查询依然慢,且执行计划不稳定,容易随数据分布变化而劣化。真正的根治点只有一个:让物理定义对齐,而不是在SQL层打补丁。










