explain显示key不为空但查询仍慢,是因为collation不匹配导致隐式转换使索引失效;需检查字段与连接的collation是否一致,并统一修改或显式指定collation。

为什么EXPLAIN显示key不为空,但查询还是慢?
不是索引丢了,而是MySQL在比较时做了隐式转换——比如字段是utf8mb4_general_ci,而连接默认的@@collation_connection是utf8mb4_0900_ai_ci,优化器被迫把索引列转成新规则再比,B+树就失效了。
这种情况下EXPLAIN仍可能显示key有值,但type变成ALL或index,Extra里出现Using where甚至Using filesort。真正要盯的是执行时的Handler_read_rnd_next是否暴涨。
- 先查字段真实collation:
SHOW FULL COLUMNS FROM table_name LIKE 'col_name'; - 再查会话实际规则:
SELECT @@collation_connection, @@collation_database; - JOIN语句还要额外查两边字段的collation是否完全一致
ALTER TABLE改排序规则时为什么索引更不走了?
只写CONVERT TO CHARACTER SET utf8mb4是危险操作——它会按当前server默认collation覆盖字段,很可能把原utf8mb4_unicode_ci变成utf8mb4_0900_ai_ci,反而加剧错配。
安全做法必须显式锁定collation:
- 用
MODIFY重定义字段:ALTER TABLE users MODIFY username VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - 大表不能停写?换
CHANGE配合pt-online-schema-change - 改完立刻
SHOW CREATE TABLE验证,再跑EXPLAIN确认key列出现索引名
应用连上后,改表白忙活?
表和字段改得再整齐,如果连接层没对齐,查询时仍触发转换。@@collation_connection才是SQL中字符串字面量的“出生户口”,ORM或驱动不声明,MySQL就fallback到server默认值。
- JDBC连接串加:
?useUnicode=true&characterEncoding=utf8mb4&collationConnection=utf8mb4_unicode_ci - PHP mysqli连接后执行:
mysqli_query($conn, "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"); - 命令行客户端启动加:
--default-character-set=utf8mb4 --collation-server=utf8mb4_unicode_ci
漏掉collation=这部分,前面所有操作都可能白做。
JOIN一上就慢,单表却正常?
这是最容易被忽略的场景:两个表字段都是utf8mb4,但一个是utf8mb4_general_ci,另一个是utf8mb4_0900_ai_ci,MySQL在join buffer里做全量转换,索引根本没机会参与。
修复必须两端一起动:
- 查JOIN字段各自的collation:
SHOW FULL COLUMNS FROM t1 LIKE 'col';和SHOW FULL COLUMNS FROM t2 LIKE 'col'; - 统一修改其中一端(推荐改老表):
ALTER TABLE t2 MODIFY col VARCHAR(100) COLLATE utf8mb4_general_ci; - 临时应急可在ON条件里显式cast:
ON t1.col = t2.col COLLATE utf8mb4_general_ci,但别长期依赖
字符集本身没问题,问题永远出在collation的“对齐”上——差一个下划线,索引就形同虚设。











