key为空但possible_keys有值说明索引存在但未被选用,主因是优化器估算全表扫描更优,常见于最左前缀不匹配、隐式类型转换、函数操作、统计信息过期或高比例匹配等场景。
执行计划里 key 为空但 possible_keys 有值,说明索引可能缺失
navicat 的执行计划表格中 key 列为空、而 possible_keys 有值,最常见原因不是优化器“挑错了”,而是那个索引压根不存在——你查的字段组合根本没建索引。这种情况在 navicat 还原数据库后特别高频:备份文件没带 create index 语句,或还原时漏勾了「索引」选项。
实操建议:
- 先运行
SHOW INDEX FROM table_name,确认输出里有没有你预期的索引名和字段顺序 - 打开你的 .sql 备份文件,全文搜索
CREATE INDEX或KEY,看是否真包含该索引定义 - 如果是 Navicat 的
.nb3格式备份,它默认不存 DDL,还原后必须手动补索引 - 别依赖 Navicat「设计表 → 索引」界面点选添加——它生成的 SQL 容易漏
USING BTREE或大小写不一致,直接手写CREATE INDEX更稳
type = ALL 且 rows 值小,但 key 仍为空,大概率是索引根本没建
当 EXPLAIN 显示 type: ALL、rows 只有几十或几百,key 却是空的,这不是优化器“算错了”,而是连索引都没定义。MySQL 在数据量极小时会倾向全表扫描,但前提是——它得先“看到”可用索引。如果 possible_keys 也为空,那基本可以断定:你要的索引不在表结构里。
实操建议:
- 用
SHOW CREATE TABLE table_name看建表语句末尾,确认没有漏掉KEY idx_name (col1, col2)这类定义 - 检查 WHERE 条件字段是否全为字符串类型却用了数字字面量(如
WHERE status = 1而 status 是VARCHAR),这种隐式转换会让 MySQL 直接跳过建了的索引,但此时possible_keys通常不为空——可借此和“真缺失”区分 - 联合索引必须严格匹配最左前缀:建了
(user_id, status),但查询只写WHERE status = 'active',这个索引就完全不可用,possible_keys也会为空
Navicat 执行计划不显示索引名,怎么确认是不是真缺
Navicat 默认渲染的执行计划表格精简了字段,key 列为空容易误判。真正要验证“是不是真没建”,不能只盯表格,得看底层输出。
实操建议:
- 右键执行计划结果表格 → 选「显示所有列」,重点看
key_len和ref:如果key_len是 0 且ref是NULL,基本坐实没走任何索引 - 在查询前加
EXPLAIN FORMAT=JSON(MySQL 5.6+),Navicat v15.5+ 会解析出used_indexes字段,明确告诉你用了哪些索引 - 如果用的是旧版 Navicat 或连接 MariaDB,直接在查询窗口运行
EXPLAIN SELECT ...,看文本输出里的key和possible_keys是否都为空 - PostgreSQL 用户注意:
EXPLAIN输出里要找Index Scan using idx_name on table_name这类提示,不是靠key列
ANALYZE TABLE 后 key 还是空,那八成就是索引缺失了
ANALYZE TABLE 是刷新统计信息的命令,能解决“索引存在但优化器误判不走”的问题。但如果执行完它,EXPLAIN 的 key 列还是空,且 possible_keys 也为空,那就不是统计不准,而是结构上确实没定义那个索引。
实操建议:
- 先跑
ANALYZE TABLE table_name,排除统计信息过期干扰 - 再立刻跑
EXPLAIN,如果possible_keys仍为空,立刻转向SHOW CREATE TABLE查结构 - 别在高峰期执行
ANALYZE TABLE,它在 MySQL 5.7+ 虽是轻量采样,但仍可能短暂加读锁 - 对大表,
ANALYZE TABLE可能耗时,但它的作用只是“让优化器看清现状”,无法凭空变出缺失的索引
possible_keys 为空才是铁证;一旦它有值,问题就转向字段顺序、类型匹配或统计信息——这两类场景的排查路径完全不同。











