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

索引失效不是“没建好”,而是 MySQL 在比较前发现字段、参数、连接三者字符集或 COLLATION 不一致,主动放弃使用索引——它宁可全表扫描,也不愿返回错误结果。
查清哪一层的字符集/排序规则不匹配
别猜,直接查。三层必须对齐:字段定义、连接会话、SQL 字面量。常见错误是字段用 utf8mb4_unicode_ci,而连接默认 utf8mb4_0900_as_cs 或更糟的 latin1_swedish_ci。
- 查字段真实定义:
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 COLLATION('test');返回值应与字段的Collation完全一致 - 存储过程中尤其危险:
_utf8mb4'xxx' COLLATE utf8mb4_unicode_ci这种显式声明,若和字段COLLATE不同,照样触发隐式转换
WHERE 条件里字符串不加引号是硬伤
WHERE phone = 13800138000 看似省事,实则灾难。MySQL 会把 phone(VARCHAR)逐行转成数字比对,B+ 树索引基于原始字符串构建,转换后无法定位,EXPLAIN 显示 key 为 NULL、type 为 ALL。
- 必须写成:
WHERE phone = '13800138000' - 哪怕字段是
CHAR、TEXT或ENUM,只要类型是字符串,值就必须是字符串字面量 - ORM 框架也要检查:MyBatis 的
#{}是预编译,安全;但手拼 SQL 或用${}仍可能漏引号 - 这不是“习惯问题”,是 MySQL 类型系统强制对齐的底层规则
最麻烦的点在于:它不报错,只悄悄变慢。等业务扛不住才去查 EXPLAIN,而那时往往已牵扯连接配置、表结构、SQL 写法三层,修复成本陡增。建表阶段就定死 utf8mb4 + utf8mb4_0900_as_cs,比出问题再改强十倍。











