索引元数据与B+树结构脱节导致失效,需用SHOW INDEX查Cardinality是否为0或NULL,优先执行ALTER TABLE FORCE强制重建并立即ANALYZE TABLE更新统计信息。

还原后索引“还在”,但查询变慢、EXPLAIN 显示 type: ALL,基本可以断定:不是索引丢了,而是索引元数据和底层 B+ 树结构脱节了——尤其是用物理拷贝(如直接复制 .ibd 文件)或不带 --skip-extended-insert 的 mysqldump 恢复时,InnoDB 的统计信息、页链关系、聚簇索引与二级索引之间容易失同步。
怎么确认索引是不是真失效了
别只看 SHOW CREATE TABLE 或 DESCRIBE ——它们只返回建表语句,不反映引擎层真实状态。关键要看 SHOW INDEX FROM t 的输出:
-
Cardinality为NULL或0:说明优化器已放弃该索引,大概率不可用 -
Sub_part非空但Cardinality极低(比如列有百万唯一值,却显示 10):索引可能严重碎片化或未重建完成 - 同一张表多个索引,只有部分
Cardinality异常:说明问题可能局部,非全表损坏
InnoDB 表该用 ALTER TABLE FORCE 还是 ENGINE=InnoDB
两者都会重建表,但行为有本质差别:
-
ALTER TABLE t ENGINE=InnoDB是隐式重建,MySQL 可能跳过某些校验,在元数据严重错位时“假装成功” -
ALTER TABLE t FORCE强制触发全量重刷:清空旧聚簇索引页、重建所有二级索引、重写ibdata1中的元数据引用,对恢复后不一致更可靠 - 大表务必加
ANALYZE TABLE t在重建后立即执行——否则优化器仍用旧Cardinality做决策,EXPLAIN看起来还是走全表扫描 - 如果表很大且不能锁太久,优先用
pt-online-schema-change替代,避免业务中断
MyISAM 表索引损坏必须用 REPAIR TABLE + myisamchk
InnoDB 不支持 REPAIR TABLE,但 MyISAM 必须依赖它,因为索引文件 .MYI 和数据文件 .MYD 完全分离:
- 先跑
CHECK TABLE t:若返回error或record delete-link chain broken,说明索引断裂 -
REPAIR TABLE t QUICK仅重建索引树,快但不修数据逻辑;若CHECK TABLE报数据损坏,必须用REPAIR TABLE t EXTENDED - 修复失败常见原因是
tmpdir空间不足——REPAIR会生成临时.TMD文件,大小 ≈ 原.MYI×2,查SELECT @@tmpdir确认空间 - 修复完立刻执行
FLUSH TABLES或重启 MySQL,否则缓存里的旧索引描述符还在生效
重建后怎么验证索引真的修好了
命令返回 OK 不代表业务可用,静默失效最危险:
- 对含
UNIQUE索引的表,立刻查重复:SELECT key_col, COUNT(*) FROM t GROUP BY key_col HAVING COUNT(*) > 1,防止修复过程跳过冲突行 - 用
EXPLAIN SELECT ...对比重建前后:key列是否命中预期索引名,rows是否从几十万降到几百 - 如果查询仍不走索引,别急着再重建——先检查是否触发了隐式类型转换、函数包裹、
OR条件混用非索引列等常见失效场景
最容易被忽略的是:修复动作本身没出错,但后续没更新统计信息、没清缓存、没验证唯一性约束,导致问题从“明显变慢”退化成“偶发错结果”。重建只是第一步,验证才是闭环的关键一环。


















