全文索引搜不到中文短词,因默认ft_min_word_len=4且字符集非utf8mb4;需调小词长、重建索引、用布尔模式查询,并确保查询条件独立以触发索引。

全文索引建不起来?检查 ft_min_word_len 和字符集
MySQL 默认只对 4 字符以上单词建立全文索引,中文分词又没原生支持,所以建完 CREATE FULLTEXT INDEX 却搜不到短词或单字,不是你 SQL 写错了,是底层配置卡住了。
常见错误现象:MATCH() AGAINST() 返回空结果,哪怕字段里明明有“云”“AI”“5G”这种两字词;SHOW INDEX FROM table_name 显示索引存在,但 SELECT COUNT(*) 配合全文查询却为 0。
- 确认当前最小词长:
SHOW VARIABLES LIKE 'ft_min_word_len';,默认是 4,中文几乎全被过滤 - 修改需重启 MySQL(5.7 及以前)或动态设置(8.0+ 支持
SET GLOBAL ft_min_word_len = 2;),但必须同时重建索引:ALTER TABLE t DROP INDEX ft_idx; ALTER TABLE t ADD FULLTEXT INDEX ft_idx(col); - 表和列的字符集必须是
utf8mb4,且排序规则推荐utf8mb4_unicode_ci或utf8mb4_0900_as_cs;用latin1或utf8(非 mb4)会导致中文被截断成乱码,全文索引直接失效
MATCH() AGAINST() 搜不到结果?注意模式和停用词
默认自然语言模式(IN NATURAL LANGUAGE MODE)会忽略停用词、按相关性排序,但不会报错——你搜“的”“是”“在”,返回空很合理,不是 bug,是设计如此。
使用场景:想快速找“包含关键词且相关度高”的记录,比如文章标题匹配“数据库优化”,而不是精确命中。
- 中文搜索慎用自然语言模式:停用词表(
ft_stopword_file)默认含大量中文虚词,且不支持同义扩展。真要搜中文,优先切到布尔模式:MATCH(col) AGAINST('+mysql +索引' IN BOOLEAN MODE) - 布尔模式下
+表示必须包含,-表示必须排除,*是词干通配(如'myq*' → 'mysql'),但仅作用于词尾,且要求词干本身在索引中存在 - 布尔模式不计算相关性,
ORDER BY MATCH() DESC无效;若需要排序,得自己加权重逻辑或换 Elasticsearch
为什么 LIKE '%关键词%' 比全文索引还快?
不是全文索引慢,是你没让 MySQL 用上它——最常见原因是查询条件里混用了非全文字段,或者 WHERE 后跟了其他索引无法覆盖的条件,导致优化器放弃走全文索引。
性能影响:全文索引本质是倒排表,MATCH() AGAINST() 必须是 WHERE 子句的独立条件,不能嵌套在函数里,也不能和 OR、NOT IN 等一起用,否则退化为全表扫描。
- 检查执行计划:
EXPLAIN SELECT * FROM t WHERE MATCH(title) AGAINST('事务');,看type是否为fulltext,key是否显示你的全文索引名 - 避免写成:
WHERE MATCH(title) AGAINST('事务') AND status = 1—— 如果status没单独建索引,MySQL 很可能放弃全文索引,改用status索引再回表过滤 - 全文索引不支持前导通配(
*sql),也不支持模糊距离(如编辑距离),这类需求别硬扛,该上 Ngram 分词或外部检索就上
线上加全文索引卡住?小心锁表和磁盘爆满
MySQL 5.6+ 对 ADD FULLTEXT INDEX 支持 Online DDL,但前提是表引擎是 InnoDB 且没外键依赖;一旦失败,就会退化为 copy table,大表直接阻塞写入、撑爆 tmpdir。
兼容性影响:MyISAM 全文索引支持布尔模式更早,但不支持事务、崩溃恢复差;InnoDB 从 5.6 开始支持,但早期版本(如 5.6.4)对中文分词依然乏力。
- 加索引前先评估数据量:
SELECT COUNT(*) FROM t;超过 500 万行建议选低峰期,或用 pt-online-schema-change - 监控临时目录:
SHOW VARIABLES LIKE 'tmpdir';,全文索引构建过程会生成大量临时文件,空间不足会报错ERROR 1034 (HY000): Incorrect key file - 如果表有大量重复值(如日志表的固定状态字段),全文索引体积可能比原表还大,因为倒排表存储的是“词→文档ID列表”,高频词会拖慢插入性能
全文索引不是“开了就能搜中文”,它对词长、字符集、查询写法、执行路径都敏感;真正上线前,至少拿真实语料跑一遍 EXPLAIN 和慢查日志,别只信测试数据。











