MySQL 8.0 全文索引失效是因底层存储格式不兼容,旧版索引元数据可见但优化器拒绝使用;必须通过 ALTER TABLE 原子操作重建,并配合 ngram 配置、FLUSH TABLES 及 OPTIMIZE TABLE 确保生效。

MySQL 8.0 不兼容旧版全文索引的底层存储格式,直接升级后 FULLTEXT 索引会失效或无法使用——这不是配置问题,而是 InnoDB 全文索引结构在 5.6/5.7 和 8.0 之间发生了不兼容变更。
为什么 EXPLAIN 显示 key 为 NULL,但 SHOW INDEX 却能看到 FULLTEXT?
这是最典型的误判信号。MySQL 8.0 仍能读取旧版本创建的 FULLTEXT 索引元数据(所以 SHOW INDEX 可见),但优化器拒绝在执行计划中使用它,因为底层倒排索引的物理结构已不被新版本解析器识别。
- 运行
EXPLAIN SELECT * FROM t WHERE MATCH(col) AGAINST('xxx'),若key列为NULL、type为ALL,基本可确认索引未被启用 - 检查表引擎和版本来源:
SELECT ENGINE, VERSION FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't';若VERSION是10(对应 5.7)或更低,说明索引是旧格式 - 不要依赖
ANALYZE TABLE—— 它对全文索引统计信息无效,也无法修复结构不兼容
重建 FULLTEXT 索引必须用 ALTER TABLE,不能只 DROP + CREATE
MySQL 8.0 要求全文索引重建必须通过 ALTER TABLE ... DROP INDEX + ADD FULLTEXT 的原子操作完成,否则可能残留损坏的索引状态。
- 错误做法:
DROP INDEX ft_idx ON t后再CREATE FULLTEXT INDEX ft_idx ON t(col)—— 这会触发 bug,导致后续MATCH报错ERROR 1862 (HY000) - 正确做法:
ALTER TABLE t DROP INDEX ft_idx, ADD FULLTEXT INDEX ft_idx (col) - 若原索引跨多列,必须完整重写列列表:
ADD FULLTEXT INDEX ft_idx (col1, col2),不能省略任一列 - 重建期间表会被锁(InnoDB 行锁级别,但 DDL 会触发短暂的元数据锁),建议在低峰期执行
注意 ngram 分词器配置是否匹配旧逻辑
MySQL 5.7 默认用 ngram 分词器处理中文,但 8.0 中该分词器行为有细微差异:默认 ngram_token_size 仍为 2,但字符串预处理(如标点剥离、空格归一)更严格。
- 检查当前设置:
SELECT @@ngram_token_size, @@ft_min_word_len;若旧库曾调大过ft_min_word_len,需在 8.0 中显式设回(如SET GLOBAL ft_min_word_len = 2) - 重建索引前,确认
my.cnf中已配置:ngram_token_size=2(或按需调整),且该配置在服务启动时加载生效 - 重建后必须重启 MySQL 或至少执行
FLUSH TABLES,否则新分词配置不生效 - 验证分词效果:
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE WHERE WORD LIKE 'xxx'(查缓存)或建测试表跑MATCH ... AGAINST对比结果
真正容易被忽略的是:全文索引重建后,INFORMATION_SCHEMA.INNODB_FT_CONFIG 表里的 OPTIMIZE 值可能仍为 0,表示尚未完成后台合并。此时查询可能返回不全结果,需手动触发 OPTIMIZE TABLE t 确保索引彻底就绪。


















