索引失效是因字段、连接会话、sql字面量三者collation不一致导致mysql主动弃用索引;须用show full columns、select @@collation_connection、show create table精准比对,并统一为utf8mb4_0900_as_cs,修改时必须同时指定character set和collate。

索引失效不是“没建好”,而是 MySQL 在比较前发现字段、参数、连接三者字符集或 COLLATION 不一致,主动弃用索引——它宁可全表扫描,也不愿返回错误结果。
查清哪一层的字符集/排序规则不匹配
别猜,直接查。三层必须对齐:字段定义、连接会话、SQL 字面量。
- 查字段真实定义:
SHOW FULL COLUMNS FROM users LIKE 'username';,重点看Collation列 - 查当前连接生效的规则:
SELECT @@collation_connection, @@character_set_client; - 查表整体字符集:
SHOW CREATE TABLE users;,确认DEFAULT CHARSET和列级COLLATE是否混用 - JOIN 失效时,两边表都要查,对比关联字段的
character_set_name和collation_name(可用INFORMATION_SCHEMA.COLUMNS)
ALTER TABLE 修改字段时必须同时指定 CHARACTER SET 和 COLLATE
只改 CHARACTER SET 不改 COLLATE,大概率白忙——MySQL 实际比对的是排序规则,不是字符集本身。
- 例如字段当前是
VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,想对齐到utf8mb4_0900_as_cs,就得写全:ALTER TABLE users MODIFY username VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs; - 不能只写
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4;——它会保留原COLLATE,可能仍是utf8mb4_unicode_ci - 修改过程会锁表(除非满足
ALGORITHM=INPLACE条件),大表务必低峰期操作 - 改完立刻
SHOW CREATE TABLE验证,再跑EXPLAIN看key是否出现索引名
连接层不统一,改表也没用
应用连上数据库后,@@collation_connection 决定了 SQL 中字符串字面量(如 'abc')的默认排序规则。如果 ORM 或驱动没显式指定,MySQL 就 fallback 到该字符集的默认 COLLATE,很可能和你刚改好的字段不一致。
- Java JDBC 连接串加:
?useUnicode=true&characterEncoding=utf8mb4&collationConnection=utf8mb4_0900_as_cs - PHP mysqli 连接后立刻执行:
mysqli_set_charset($conn, 'utf8mb4');并确认SET NAMES utf8mb4 COLLATE utf8mb4_0900_as_cs; - 验证是否生效:
SELECT CHARSET('测试'), COLLATION('测试');——返回应与字段一致
最麻烦的是它不报错,只悄悄变慢;EXPLAIN 里 key 为 NULL、type 是 ALL 才是关键信号。修复顺序必须是:先统一连接层,再校准字段定义,最后验证 JOIN 和 WHERE 行为——漏掉任意一层,索引就掉一层。











