MySQL 5.6+ InnoDB 全文索引词长限制由 innodb_ft_min_token_size 控制(非 ft_min_word_len),运行时不可修改,需停库改配置、删旧索引、重启后重建;停用词表和分词行为同样仅在建索引时生效,且全文检索存在缓存延迟与事务可见性问题。

MySQL 5.6+ 的 FT_MIN_WORD_LEN 无法运行时修改
InnoDB 全文索引对词长有硬性限制,默认只索引长度 ≥ 3 的词(FT_MIN_WORD_LEN=3),且这个值在 MySQL 启动时读取,**运行中改 my.cnf 并 SET GLOBAL 无效**。
常见错误现象:SELECT MATCH(title) AGAINST('a') IN NATURAL LANGUAGE MODE 永远返回 0,哪怕表里真有单字母内容;或者重建全文索引后仍搜不到短词。
- 必须停库 → 修改配置文件中的
innodb_ft_min_token_size(注意:InnoDB 用这个参数,不是ft_min_word_len,后者只影响 MyISAM) - 删掉旧的全文索引:
ALTER TABLE t DROP INDEX ft_idx - 重启 MySQL,再重建索引:
ALTER TABLE t ADD FULLTEXT INDEX ft_idx (title) - 重建期间会触发全文索引解析,新词长才生效;不重建,老索引仍按旧规则缓存
用 IN NATURAL LANGUAGE MODE 还是 IN BOOLEAN MODE?
两者底层分词、权重、语法完全不同,选错会导致“明明有数据却查不到”或“结果排序反直觉”。
自然语言模式(IN NATURAL LANGUAGE MODE)自动过滤停用词、按 TF-IDF 算相关度,适合简单搜索;布尔模式(IN BOOLEAN MODE)支持 +/-/* 等操作符,但停用词列表仍生效,且不计算相关度得分(永远返回 1)。
- 想搜“mysql tutorial”,又希望“tutorial”权重更高?用自然语言模式 —— 它会返回浮点数得分
- 要精确排除某词,比如“mysql -performance”?必须用布尔模式,自然语言模式不支持减法
- 布尔模式下
AGAINST('innoDB*')可以匹配InnoDB、InnoDB,但*只能出现在末尾,且前面至少 3 字符(受innodb_ft_min_token_size限制) - 停用词不可禁用:即使设
innodb_ft_enable_stopword=OFF,某些极短词(如 “a”, “the”)仍被硬编码忽略,无法索引
innodb_ft_server_stopword_table 自定义停用词表不起作用?
很多人建了自定义停用词表、配了 innodb_ft_server_stopword_table,却发现词还是被过滤了——根本原因是:**该配置只在创建全文索引时生效,已有索引不会自动重载停用词**。
使用场景:你想让 “api”、“sdk” 这类技术缩写不被当停用词过滤,但默认停用词表里包含了它们。
- 先确认表结构符合要求:
CREATE TABLE my_stopwords(value VARCHAR(30)) ENGINE = INNODB;,字段名必须叫value,类型不能是 TEXT - 插入自定义词:
INSERT INTO my_stopwords VALUES ('api'), ('sdk'); - 设置变量:
SET GLOBAL innodb_ft_server_stopword_table = 'test/my_stopwords'; - 最关键一步:删掉旧全文索引 + 重建,否则停用词表只是摆设
- 注意:该变量只影响后续新建的索引,不影响已存在的索引;且重启后需重新
SET GLOBAL
为什么 SELECT ... MATCH() AGAINST() 返回空结果,但 LIKE 能查到?
这是最常被误判为“全文索引坏了”的情况,其实大概率是分词或事务隔离导致的。
典型表现:刚 INSERT 一条含 “elasticsearch” 的记录,立刻 MATCH() AGAINST() 查不到,但 LIKE '%elastic%' 能命中。
- InnoDB 全文索引不是实时更新的:它依赖后台线程合并缓存的变更,延迟通常几秒;可查
INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE看未合并的 token - 当前事务未提交?全文检索默认读已提交(READ COMMITTED)快照,未提交的 INSERT 对 MATCH 不可见
- 字段类型是否为
TEXT或VARCHAR?TINYTEXT和带utf8mb4_0900_as_cs这类新 collation 的字段,在某些 MySQL 版本中可能触发分词异常 - 试试强制刷新:
OPTIMIZE TABLE t(会重建索引并合并缓存),但生产环境慎用,锁表时间长
真正麻烦的是分词粒度问题:像 “user_id” 默认被切为 “user” 和 “id”,中间下划线直接丢弃;如果业务依赖下划线分隔,就得提前预处理字段值,或者换用 Ngram 分词器(MySQL 原生不支持,得靠外部工具或升级到 8.0+ 的 ngram parser 插件)。










