ALTER TABLE ... ADD FULLTEXT在InnoDB中不报错却查不到结果,是因为存在七项硬性准入门槛:必须显式指定ENGINE=InnoDB;字段仅限VARCHAR/TEXT(CHAR索引不显示);字符集需为utf8mb4;innodb_ft_min_token_size默认为3导致短词被过滤;停用词表默认启用且不可热替换;中文必须显式声明WITH PARSER ngram;MATCH()字段顺序、数量、大小写须与索引定义完全一致。

InnoDB 在 MySQL 5.6.4+ 已完全可替代 MyISAM 做全文检索,不是“勉强能用”,而是从事务一致性、并发能力、运维规范三方面彻底覆盖其旧有优势。
为什么 ALTER TABLE ... ADD FULLTEXT 在 InnoDB 里不报错却查不到结果?
这不是功能缺失,而是 InnoDB 对全文索引设置了硬性准入门槛,任何一项不满足都会静默失效:
-
ENGINE=InnoDB必须显式确认,SHOW CREATE TABLE table_name里看到的不是MyISAM或空值 - 索引字段只能是
VARCHAR或TEXT类型;CHAR列上建的FULLTEXT索引在SHOW INDEX中根本不会出现 - 字符集必须是
utf8mb4(或latin1),utf8(即utf8mb3)在 MySQL 8.0+ 已被弃用,且对部分 emoji 分词支持异常 - 默认最小词长是
@@innodb_ft_min_token_size = 3,搜"go"或"a"会被直接过滤,不报错也不返回 - 停用词表默认启用,
"the"、"and"、"is"全部跳过;改innodb_ft_server_stopword_table后必须重启 MySQL(InnoDB 不支持运行时热替换)
中文搜索必须配 ngram,但不是装插件而是显式声明
MySQL 原生分词器按空格和标点切词,对中文无效。InnoDB 支持中文,但必须主动启用 ngram 解析器,否则索引建了也白建:
- 建表或加索引时必须写明
FULLTEXT(content) WITH PARSER ngram,缺WITH PARSER ngram就等于没开 -
ngram_token_size默认为 2(二元分词),若设为 1,会按单字切,召回率低、噪音高;设为 3 又可能漏掉常用双音节词 -
ngram是编译内置功能,不是靠INSTALL PLUGIN加载,所以不能用SHOW PLUGINS查,也不能靠开关控制 - 查询时仍用标准语法:
MATCH(content) AGAINST('数据库' IN NATURAL LANGUAGE MODE),无需额外改写
MATCH() AGAINST() 返回空结果,大概率是字段定义与查询不严格匹配
InnoDB 要求 MATCH() 中的字段列表,和 FULLTEXT 索引定义的字段顺序、数量、名称完全一致——差一个字母、多一个字段、顺序颠倒,都会退化为全表扫描(EXPLAIN 显示 type=ALL, key=NULL):
- 如果索引定义是
FULLTEXT(title, content),那查询必须写成MATCH(title, content) AGAINST(...),不能写成MATCH(content, title)或MATCH(title) - 字段名大小写敏感:表定义是
content,就不能写成CONTENT或Content - 布尔模式需显式声明:
AGAINST('+mysql -oracle' IN BOOLEAN MODE),漏掉IN BOOLEAN MODE会走自然语言模式,行为完全不同 - 通配符只支持右模糊:
'search*'有效,'*search'或'*sea*'都不支持
真正容易被忽略的,是 InnoDB 全文索引的异步合并机制:新插入的文本不会立刻可搜,后台线程要等缓存积攒到阈值或触发 OPTIMIZE TABLE 才合并进主索引。这意味着刚写入的数据查不到,不是 bug,是设计使然;想强制刷新,只能执行 OPTIMIZE TABLE(会锁表),或调大 innodb_ft_aux_table 相关参数降低延迟——但这会影响写入吞吐。


















