MySQL全文索引查不到“夏”是因为默认词长限制(innodb_ft_min_token_size=4),导致单字词未被索引;需调小该值、重建索引并启用ngram分词器支持中文短词。

MySQL全文索引能实现比 LIKE '%keyword%' 快几十倍的关键词检索,但直接建索引、写 MATCH() AGAINST() 很可能查不到结果——根本原因通常是默认词长限制、引擎不匹配或模式误用。
为什么 MATCH(title, content) AGAINST('夏') 查不到“夏季”?
MySQL默认只索引长度 ≥ 4 的词(innodb_ft_min_token_size = 4),所以“夏”“防水”“手表”这类短词根本不会进倒排索引。即使你插入了含“夏季”的数据,查询时也相当于在空索引里找东西。
- 对 InnoDB 表:必须修改
innodb_ft_min_token_size(例如设为 1),然后 重建全文索引(ALTER TABLE t DROP INDEX ft_idx; ALTER TABLE t ADD FULLTEXT ft_idx (title);) - 对 MyISAM 表:改的是
ft_min_word_len,同样需重启 MySQL +REPAIR TABLE t QUICK; - 改完参数后,旧数据不会自动重分词,必须
OPTIMIZE TABLE t;或重新 INSERT 才生效
MATCH() AGAINST() 的三种模式怎么选?
自然语言模式(默认)适合简单搜索,但不支持逻辑符;布尔模式才是关键词检索主力,它允许精确控制词的包含/排除关系。
- 自然语言模式:
AGAINST('防水运动手表')→ 自动拆词、按 TF-IDF 排序,但无法强制要求“防水”必须出现 - 布尔模式:
AGAINST('+防水 +运动 -培训班' IN BOOLEAN MODE)→+表必须含,“-”表必须不含,“>”可提升权重 - 查询扩展模式:
AGAINST('数据库' WITH QUERY EXPANSION)→ 会自动加入高频相关词(如“MySQL”“SQL”),但容易漂移,慎用于生产
中文检索为什么总失败?
MySQL 原生分词器对中文无效——它把整段中文当一个 token 处理(比如“防水运动手表”被当做一个 7 字词),而默认 innodb_ft_min_token_size=4,导致实际没建任何有效索引。
- 5.7.6+ 版本必须启用
ngram插件:SET GLOBAL ngram_token_size = 2;,建索引时显式指定:FULLTEXT(title) WITH PARSER ngram - 否则只能退到外部方案:用 Elasticsearch 预处理分词,或应用层切好词再存入额外字段(如
search_keywords) - 停用词表(
innodb_ft_stopword_table)会影响中文效果,建议清空或自定义,避免“的”“了”等虚词干扰
为什么加了全文索引,SELECT ... MATCH() AGAINST() 还是慢?
全文索引不是万能加速器——它只在 WHERE 子句中用 MATCH() AGAINST() 时才走索引;一旦混用其他条件(如 AND status = 1),优化器可能放弃全文索引,回退全表扫描。
- 确保查询中
MATCH() AGAINST()是WHERE的核心过滤条件,避免前置无关AND - 联合全文索引字段顺序有影响:如果常搜
title,就把title放在FULLTEXT(title, content)的前面 - 全文索引不支持
ORDER BY加速,如需按时间排序,得靠二级索引配合,不能指望MATCH()返回结果自带顺序
最常被忽略的一点:全文索引对单字、双字中文词的支持,完全依赖 ngram_token_size 和重建动作,改完配置不 OPTIMIZE 或不重建索引,等于没改。


















