索引失效是因字段、连接层、sql字面量三者collation不匹配导致mysql主动弃用索引;须用show full columns、select @@collation_connection和show create table分别确认三层真实值,统一为相同collate(如utf8mb4_0900_as_cs)并显式配置连接参数。

索引失效不是没建索引,而是 MySQL 在执行前发现字段、连接层、SQL 字面量三者 COLLATION 不匹配,主动弃用索引——它宁可全表扫描,也不愿返回错误结果。
怎么确认是 COLLATION 不一致导致的索引失效
别靠经验猜,直接查三层真实值:
-
SHOW FULL COLUMNS FROM users LIKE 'username'—— 看输出里Collation列,这是字段级真实排序规则 -
SELECT @@collation_connection, @@character_set_client—— 连接层决定'abc'这类字面量按什么规则解释 -
SHOW CREATE TABLE users—— 确认表默认CHARACTER SET和列级是否混用COLLATE
常见坑:字段是 utf8mb4_unicode_ci,但 @@collation_connection 是 latin1_swedish_ci 或 utf8mb4_0900_as_cs。哪怕字符集都是 utf8mb4,只要 COLLATE 不同,就触发隐式转换。
ALTER TABLE 修改字段 COLLATION 必须同时指定 CHARACTER SET 和 COLLATE
只改 CHARACTER SET 不改 COLLATE,等于白干。MySQL 比较时依赖的是排序规则,不是字符集本身。
- 错误写法:
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4—— 只改表默认值,不改已有字段的COLLATE - 错误写法:
ALTER TABLE users MODIFY username VARCHAR(50) CHARACTER SET utf8mb4—— 不带COLLATE,字段Collation仍保持原样 - 正确写法:
ALTER TABLE users MODIFY username VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs—— 必须同时指定二者,且值要和关联字段完全一致
大表操作会锁表重建索引,务必在低峰期执行;MySQL 8.0+ 且字段无全文索引时,可加 ALGORITHM=INPLACE 减少锁表时间。改完立刻 SHOW CREATE TABLE 验证字段定义,再跑一遍 EXPLAIN,确认 key 列出现索引名才算生效。
连接层 collation_connection 不统一,改表也白搭
字段层改对了,但应用连进来时 @@collation_connection 还是错的,WHERE 条件里的字符串字面量仍会被转成另一套规则再比对,索引照样失效。
- JDBC 连接串必须显式加:
?useUnicode=true&characterEncoding=utf8mb4&collationConnection=utf8mb4_0900_as_cs - PDO 要设
PDO::ATTR_EMULATE_PREPARES => false并在 DSN 中声明;charset=utf8mb4;collation=utf8mb4_0900_as_cs - 命令行客户端启动时加
--default-character-set=utf8mb4 --collation-server=utf8mb4_0900_as_cs
ORM 或驱动没显式指定时,MySQL fallback 到服务端默认值,极易错配。漏掉 collationConnection= 这部分,前面所有表和字段改得再整齐,查询时仍可能触发转换。
JOIN 场景下两边字段 COLLATION 必须完全一致
两张表关联字段字符集或排序规则不同,哪怕都是 utf8mb4,只要 COLLATION 不同,MySQL 就无法直接走索引做 hash join 或 ref lookup。
- 检查关联字段:
SHOW FULL COLUMNS FROM t1 LIKE 'org_id'和SHOW FULL COLUMNS FROM t2 LIKE 'org_id' - 修复原则:宁可改小表字段,也不要让
ON条件做隐式转换;ON t1.org_id = t2.org_id中任意一边被转,索引就废 - 临时绕过(仅限紧急):
ON t1.org_id = CONVERT(t2.org_id USING utf8mb4) COLLATE utf8mb4_0900_as_cs—— 但会让t2.org_id上的索引完全失效,且执行计划可能退化为Using join buffer,内存压力陡增
真正难处理的点不在语法,而在一致性维护:新表建模阶段就要定死 CHARACTER SET 和 COLLATE,否则等 JOIN 查询变慢再回溯,往往要停服、导数据、校验一致性——而最容易被忽略的,就是连接层配置是否随表结构同步更新。











