升级后索引“失效”通常是优化器选错执行路径,需先检查统计信息、optimizer_switch设置及隐式转换变化,再通过FORCE INDEX验证,真正修复应更新统计信息或调整查询写法。

升级后索引“失效”大概率不是真失效,而是优化器选错了执行路径——FORCE INDEX只是临时验证手段,不能当修复方案用。
升级后索引没走,先别急着重建
MySQL升级(尤其是5.7→8.0或8.0.x小版本间)会重算统计信息、调整索引选择策略、甚至改变隐式转换规则。你看到EXPLAIN里key为NULL或type变成ALL,未必是索引损坏,更可能是优化器基于新统计信息判断“走索引不如全表扫快”。常见诱因包括:ANALYZE TABLE未触发、直方图缺失、隐式类型转换行为变化、或optimizer_switch默认值调整。
- 执行
SHOW INDEX FROM table_name确认索引还在,且Cardinality非零 - 运行
ANALYZE TABLE table_name强制更新统计信息(升级后必须做) - 检查
SELECT @@optimizer_switch,对比升级前后差异,重点关注use_index_extensions、condition_fanout_filter等开关
用FORCE INDEX快速验证是不是优化器误判
加FORCE INDEX (idx_name)不是为了线上长期使用,而是为了交叉验证:如果加了它之后EXPLAIN显示key命中且rows显著下降,基本锁定是优化器决策问题,不是索引本身失效。
- 写法示例:
SELECT * FROM orders FORCE INDEX (idx_status_created) WHERE status = 1 AND created_at > '2026-01-01'; - 注意:只在测试环境或低峰期单条SQL中用,
FORCE INDEX会绕过优化器,可能掩盖真实性能瓶颈 - 若加了仍不走索引,说明索引本身有问题(如被
ALTER TABLE ... DISABLE KEYS禁用、或元数据损坏),需进一步查mysqlcheck --analyze
真正要修的,是统计信息和查询写法
升级后最常被忽略的其实是统计信息陈旧和查询条件“踩坑”。比如原本WHERE phone = 13800138000在老版本能隐式转成功,在新版本因严格模式被拒绝或转成0,导致索引列实际匹配0而失效。
- 对高频查询字段补直方图:
ANALYZE TABLE users UPDATE HISTOGRAM ON phone, status; - 检查所有带函数/表达式的WHERE条件:
YEAR(create_time)、CONCAT(a, b)、col + 1 = 10——这些在新版本优化器下更容易被放弃 - 用
SHOW STATUS LIKE 'Handler_read%'对比升级前后:若Handler_read_rnd激增,说明回表严重;若Handler_read_key骤降,说明索引根本没被访问
最麻烦的点往往藏在“看起来没变”的地方:比如联合索引(a, b, c),升级后优化器突然对WHERE a = ? AND c = ?放弃使用,只因b列的基数估算变了——这时候修索引不如重写查询或补覆盖索引。











