MySQL 8.0索引未丢失但被优化器拒绝使用,根本原因是校验变严:SPATIAL字段缺失NOT NULL或SRID、JSON字段直接函数查询、字符串列排序规则不匹配等导致类型不安全,触发隐式转换或索引降级;需先修正字段定义、更新统计信息、统一SRID与COLLATE,再重建索引。
不是索引“丢了”,而是优化器拒绝使用——升级后执行计划变了,EXPLAIN 显示 type=ALL、key=NULL,但 SHOW INDEX 仍能看到索引名,说明索引元数据还在,只是被跳过了。
核心原因是校验变严了:5.7 允许隐式行为(比如字段允许 NULL、默认 SRID 为 0、字符集排序规则宽松),而 8.0 要求显式声明、类型安全、规则对齐。一旦字段定义或查询写法和新规则冲突,优化器就直接放弃索引。
SPATIAL 字段没设 NOT NULL 或缺失 SRID → 索引降级为 BTREE
JSON 字段上直接用 JSON_EXTRACT() 查询 → 函数调用无法走 B+ 树索引utf8mb4_bin,但查询条件没指定 COLLATE → 触发隐式转换,索引失效(a,b,c),查询只写 WHERE b = 1 → 最左前缀断裂,5.7 和 8.0 都不走别猜,直接看 EXPLAIN 输出三项:
type 是 ALL(不是 range/ref)key 是 NULL(没选任何索引)rows 接近表总行数(比如 10 万行的表,rows=98234)三者同时出现,基本就是索引被绕过了。注意:Extra 里出现 Using filesort 不代表索引失效,可能是排序没覆盖。
很多人重建索引或加函数索引,却漏掉前置约束变更,导致静默失败:
SPATIAL 索引重建前,必须先 ALTER TABLE t MODIFY geom POINT NOT NULL SRID 4326 —— 少一个 NOT NULL,CREATE SPATIAL INDEX 就会报错,但 SHOW INDEX 还显示旧索引残留JSON 生成列没显式指定 COLLATE,和源字段排序规则不一致 → 索引建了也白建,查询时隐式转换直接跳过ANALYZE TABLE t,统计信息还是 5.7 的旧值 → 优化器误判成本,宁可全表扫也不走索引最隐蔽的坑不在“建不建索引”,而在字段定义、排序规则、统计信息这三处是否同步更新——它们不动,光改查询或加索引,大概率白忙。