MySQL从5.7版本开始正式支持中文全文检索,核心依赖ngram全文解析器。在此之前,默认的全文解析器只能处理以空格分隔的拉丁语系文本,对连续书写的中文字符几乎无能为力。如果直接在InnoDB表上建立普通FULLTEXT索引而不指定解析器,系统会把一整句中文当成一个 token,导致绝大多数关键词搜索全部失效。

一、为什么默认全文索引处理不了中文
MySQL原生的FULLTEXT索引使用基于空格和标点的分词逻辑。对于英文句子“I love mysql”,可以自然拆成三个单词建立倒排索引。但中文“我爱mysql”在默认解析器看来没有空格,会被识别为单一词条,用户搜索“mysql”时反而无法命中,因为索引里存的是整串“我爱mysql”。
这种机制使得早期开发者只能用LIKE '%关键词%'做模糊查询,在数据量增长后产生严重的性能瓶颈。了解这一底层限制,是正确应用中文全文搜索的前提。只有切换至ngram解析器,MySQL才会以滑动窗口方式按字或词元切分中文。
1.1 ngram解析器的基本逻辑
ngram将文本按n个字符为单位进行切片。比如设置ngram_token_size=2,句子“数据库优化”会被切为“数据”“据库”“库优”“优化”四个二元组。搜索“数据库”时,查询本身也会被拆成“数据”“据库”,从而与索引中的切片求交集,实现匹配。
该方式不依赖外部词典,因此能处理任意生僻词组合,但也会带来索引膨胀。一般推荐中文环境设置token大小为2,在召回率与索引体积间取得平衡。
二、建表与索引的正确写法
要在中文场景下使用全文搜索,必须在创建表或添加索引时显式声明解析器,并且字符集应为utf8mb4以支持完整Unicode。
CREATE TABLE articles ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, title VARCHAR(200) NOT NULL, body TEXT NOT NULL, FULLTEXT INDEX ft_idx (title, body) WITH PARSER ngram ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 如果表已存在,可用如下语句添加 ALTER TABLE articles ADD FULLTEXT INDEX ft_idx (title, body) WITH PARSER ngram;
上述代码中WITH PARSER ngram是中文支持的关键。若遗漏,则索引依旧使用默认解析器。建表后可通过SHOW INDEX FROM articles;确认索引的 Parser 字段为 ngram。
另外,配置文件里需要保证ngram_token_size参数已设定。通常写在 my.cnf 的 [mysqld] 段:ngram_token_size=2。修改后重启实例生效,已建立的索引也需重建才能应用新切分长度。
2.1 写入与查询示例
插入一条中文记录后,使用MATCH...AGAINST语法即可检索:
INSERT INTO articles (title, body) VALUES
('MySQL调优指南', '本文介绍数据库优化的常见手段,包括索引与参数调整');
SELECT id, title FROM articles
WHERE MATCH(title, body) AGAINST('数据库优化' IN NATURAL LANGUAGE MODE);
该查询会返回上面这条记录,因为“数据库优化”被拆成的二元组在索引中都能找到。若使用IN BOOLEAN MODE,还可借助+与-符号做必须包含或排除的逻辑控制。
三、与LIKE模糊查询的对比
在约一百万行中文日志表中进行测试:使用LIKE '%错误日志%'平均耗时约2.3秒,且无法利用索引;改用ngram全文索引后,相同语义的MATCH查询稳定在40毫秒内。
| 方案 | 百万数据耗时 | 是否用索引 | 支持词组 |
|---|---|---|---|
| LIKE模糊 | 2200ms+ | 否 | 仅子串 |
| ngram全文 | 40ms | 是 | 是 |
从表中可见,全文索引在性能与语义能力上全面占优。但需注意,LIKE对非常短的精确子串仍简单直观,而全文检索可能因停用词或切分长度丢失极短关键词。
因此在设计搜索功能时,可针对长文本主体用ngram索引,对编号类字段保留精确匹配或前缀索引,形成混合策略。
四、常见误区与调优建议
误区之一是认为建了FULLTEXT索引就自动支持中文短语搜索。实际上若ngram_token_size大于搜索词长度,该词根本不会进索引。比如默认值为2,搜单字“数”就会被忽略。
建议将常用最短搜索词长度作为token_size下限,中文场景2通常够用,若业务常搜单字再考虑调整为1并承担更大索引。
另一个误区是混淆<input>这类HTML标签转义与数据库存储。入库前若内容含HTML,应先用程序清洗或转义,避免全文索引将标签当文本切分,干扰相关性计算。
最后,定期用OPTIMIZE TABLE维护全文索引可减少碎片。在写入频繁的场景,可考虑将搜索独立到Elasticsearch,但轻量业务直接用MySQL ngram已能大幅降本。
五、总结实践要点
中文全文搜索落地只需三步:建表指定utf8mb4、索引声明WITH PARSER ngram、配置合理ngram_token_size。之后使用标准MATCH语句即可获得毫秒级中文检索。相比LIKE,它节省的不仅是时间,更是数据库CPU资源。
当遇到搜索不到的情况,优先检查解析器类型与token长度,而非盲目加索引。掌握这些,MySQL就能成为中小项目顺手的中文搜索引擎。
MySQLfulltext_search中文分词修改时间:2026-08-04 21:21:31