mysql中文全文索引需配置ft_min_word_len=1、加载ngram插件并设ngram_token_size=2,建表或添加索引时必须显式指定with parser ngram,且查询须用match against语法。

MySQL全文索引在Linux上启用前必须改配置
不改my.cnf就直接建FULLTEXT索引,大概率会失败或中文搜不准。关键不是“能不能建”,而是“建了有没有用”。
默认情况下,MySQL的ft_min_word_len是4,意味着少于4个字符的词(比如“云”“数”“库”)全被过滤掉;中文单字、双音节词根本进不了索引。另外,InnoDB默认不用ngram解析器,对中文就是按字切分——搜“数据库”实际存的是“数”“据”“库”三个孤立字,毫无语义。
- 编辑
/etc/my.cnf或/etc/mysql/my.cnf(取决于发行版),在[mysqld]段下加: -
ft_min_word_len = 1(必须设为1,否则中文词基本无效) -
plugin-load = ngram.so(加载ngram插件,MySQL 5.7+内置,无需额外安装) -
ngram_token_size = 2(设为2表示按二字词切分,“数据库”→“数据”“库”,兼顾精度与召回) - 保存后重启服务:
sudo systemctl restart mysqld(CentOS/RHEL)或sudo service mysql restart(Ubuntu/Debian)
验证是否生效:SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'ngram';返回ACTIVE才算成功。
建表时指定ngram全文索引才真正支持中文
光有配置不够,建表或改表时没指定解析器,索引还是走默认分词逻辑。InnoDB表必须显式声明WITH PARSER ngram,否则FULLTEXT只是摆设。
- 新建表时写法:
CREATE TABLE articles (id INT PRIMARY KEY, title VARCHAR(200), content TEXT, FULLTEXT(title, content) WITH PARSER ngram) ENGINE=InnoDB;- 已有表添加索引必须带上
WITH PARSER ngram: ALTER TABLE articles ADD FULLTEXT INDEX ft_title_content (title, content) WITH PARSER ngram;- 注意:添加后需重建索引才能生效,执行
OPTIMIZE TABLE articles;(尤其数据已存在时) - 别用
CREATE FULLTEXT INDEX单独建——它不支持WITH PARSER语法,会 silently 忽略解析器设置
查询必须用MATCH AGAINST,且模式选错结果就乱
用WHERE content LIKE '%xxx%'完全绕过全文索引,性能和效果都归零。哪怕建了索引,不走MATCH() AGAINST()等于没建。
- 自然语言模式(默认)适合泛搜,但中文词太短时相关性得分常为0:
SELECT *, MATCH(title, content) AGAINST('MySQL优化' IN NATURAL LANGUAGE MODE) AS score FROM articles WHERE MATCH(title, content) AGAINST('MySQL优化');- 布尔模式更可控,+ - "等操作符能强制逻辑,但注意
"数据库"必须带英文双引号,否则被拆成单字: SELECT * FROM articles WHERE MATCH(title, content) AGAINST('+数据库 +性能' IN BOOLEAN MODE);- 查单字词(如“云”)时,
IN NATURAL LANGUAGE MODE可能返回空——因为ft_min_word_len=1虽已设,但ngram只生成2字token,单字本身不入索引;此时只能用布尔模式+通配符:'云*'(注意*必须写在词尾)
常见坑:重启没生效、索引不重建、字段类型不匹配
最常卡住的地方不是配置写错,而是改完以为完事了,其实漏了关键动作。
- 改
my.cnf后忘记systemctl restart mysqld,或者重启失败但没看日志——检查sudo journalctl -u mysqld -n 50 --no-pager里有没有ngram加载错误 - 已有大量数据的表加了
FULLTEXT WITH PARSER ngram,但没跑OPTIMIZE TABLE,旧数据仍按老规则索引,新插入才生效 - 字段用了
utf8mb4_bin或latin1等非utf8mb4_unicode_ci排序规则,ngram分词可能异常;确保字段字符集是utf8mb4,排序规则推荐utf8mb4_unicode_ci - MyISAM引擎虽然也支持全文索引,但ngram只对InnoDB有效——如果表是MyISAM,
WITH PARSER ngram会被忽略,且无法通过ALTER TABLE ... ENGINE=InnoDB在线转换(大表会锁死),得CREATE TABLE ... SELECT重建
ngram不是万能解药,它本质是滑动窗口切词,对“人工智能”这种三字词,ngram_token_size=2只能切出“人工”“智能”,中间断开。真要高精度中文检索,得上Elasticsearch或专用分词服务——但对大多数内部系统,ngram配ft_min_word_len=1已是性价比最高的起点。











