
mysql 字符集不一致直接让索引失效
只要 WHERE 条件里涉及的列、参数、连接表字段三者字符集或排序规则(COLLATION)不完全一致,MySQL 就可能放弃使用索引,哪怕该列明明建了索引。这不是 bug,是设计行为——比较前必须隐式转换,而转换后无法走索引。
查清当前字段和连接参数的排序规则
别猜,用 SQL 直接看。最常出问题的是 utf8mb4_general_ci 和 utf8mb4_0900_as_cs 混用,或者客户端连接时没指定 collation_connection。
- 查字段排序规则:
SHOW FULL COLUMNS FROM table_name LIKE 'col_name'; - 查连接当前排序规则:
select @@collation_connection, @@character_set_client; - 查表默认排序规则:
SHOW CREATE TABLE table_name;
JOIN 时两边字段 COLLATION 不匹配导致全表扫描
比如左表字段是 utf8mb4_0900_as_cs,右表同名字段是 utf8mb4_unicode_ci,即使类型都是 VARCHAR,MySQL 也会拒绝用索引做等值连接,改走 Block Nested-Loop。
- 强制统一两边字段的
COLLATE:在ON或WHERE中显式加COLLATE utf8mb4_0900_as_cs - 但更稳妥的做法是修改字段本身:
ALTER TABLE t MODIFY col VARCHAR(255) COLLATE utf8mb4_0900_as_cs; - 注意:修改字段 COLLATION 可能触发表重建,大表慎操作;且
utf8mb4_unicode_ci在 8.0+ 已被标记为 deprecated
客户端连接未声明 COLLATION 导致隐式转换
Java 的 mysql-connector-java 默认不传 collationConnection,PHP 的 mysqli 如果没调用 set_charset(),都可能导致传入的字符串按服务端默认(如 latin1_swedish_ci)解析,跟字段 COLLATION 不符。
- 连接串里加参数:
?useUnicode=true&characterEncoding=utf8mb4&collationConnection=utf8mb4_0900_as_cs - 连接后立刻执行:
SET NAMES utf8mb4 COLLATE utf8mb4_0900_as_cs; - 验证是否生效:
SELECT CHARSET('测试'), COLLATION('测试');—— 返回应与字段一致
字符集问题不是“有没有”,而是“哪一层不一致”。连错一层,索引就掉一层。最麻烦的是它不报错,只悄悄变慢,查 EXPLAIN 里的 key 和 rows 才能发现异常。