MATCH()返回空而LIKE能搜到,是因为MATCH依赖倒排索引、停用词过滤和最小词长限制,且MySQL原生不支持中文分词;LIKE则是纯字符串匹配。

直接用 MATCH() + AGAINST() 搜不出结果,大概率不是语法写错,而是全文索引根本没建、模式选错、或中文根本没分词——MySQL 原生不支持中文分词,搜“数据库”默认当整个字段匹配,不是按字切。
为什么 MATCH() 返回空,但 LIKE 能搜到
这不是 bug,是机制完全不同:MATCH() 依赖倒排索引 + 停用词过滤 + 最小词长限制,而 LIKE 是纯字符串扫描。
- 英文默认过滤所有长度 ft_min_word_len = 2 并重建索引
- 中文单字(“数”、“据”、“库”)全被当停用词或过短词丢弃,原生 InnoDB 不做汉字切分
- 字段值太短(如只有 “MySQL” 一个词)或整列重复度高(全是 “test”),相关性评分低于阈值,
MATCH()直接不返回 - 验证方式:先执行
SELECT MATCH(col) AGAINST('xxx') AS score FROM t LIMIT 5;,看 score 是否为 0;再查SHOW INDEX FROM t WHERE Key_name LIKE 'fulltext%';确认索引存在
AGAINST() 的三种模式怎么选、怎么写才生效
不写模式默认是自然语言模式,它会自动排序、返回评分,但不支持逻辑操作符;想用 +、-、*,必须显式声明 IN BOOLEAN MODE。
- 自然语言模式:适合模糊关键词搜索,例如
MATCH(title) AGAINST('performance tuning')—— 它会拆词、计算 TF-IDF,但不能强制包含/排除 - 布尔模式:必须加
IN BOOLEAN MODE,否则+和-当普通字符处理;*只支持后缀通配('config*'✅,'*fig'❌);双引号包裹才算短语匹配("mysql tutorial") - 查询扩展模式(
WITH QUERY EXPANSION):会把高频共现词自动加入搜索,比如搜 “java”,可能混进 “javascript” 或 “javafx”,噪声大,生产环境基本不用
中文全文搜索必须做的两件事
MySQL 5.7+ 的 InnoDB 引擎对中文没有原生分词能力,靠空格切分,所以 “数据库优化” 整体当一个词,搜 “数据库” 就失败。
- 启用
ngram插件(MySQL 内置):启动时加配置innodb_ft_parser=ngram,建索引时指定WITH PARSER ngram,并设ngram_token_size = 2(二元分词) - 建全文索引不能只写
FULLTEXT(col),得写成FULLTEXT(col) WITH PARSER ngram,否则还是走默认空格分词 - 即使开了 ngram,单字搜索(如 “库”)仍不可靠;真正要支持细粒度中文检索,得上 Elasticsearch 或预处理分词后存入额外字段
全文索引不是写了 MATCH() 就自动有,必须手动建
MATCH(col) AGAINST('x') 不会触发隐式索引创建,没索引就报错 Can't find FULLTEXT index matching the column list 或退化为全表扫描。
- 建表时定义:在
CREATE TABLE里加FULLTEXT(content) WITH PARSER ngram(中文场景) - 已有表添加:用
ALTER TABLE t ADD FULLTEXT(content) WITH PARSER ngram,注意该列不能为NULL(InnoDB 要求NOT NULL) - MyISAM 表可直接用,但 InnoDB 要求 MySQL ≥ 5.6;5.7 默认关闭 ngram,8.0+ 更稳定些
- 索引字段类型只能是
CHAR、VARCHAR、TEXT;JSON或BLOB列不支持
最常被忽略的一点:ngram 分词的 ngram_token_size 是全局配置,改完必须重启 MySQL 才生效;而且一旦设为 2,所有 ngram 全文索引都按二字切,没法 per-table 控制。搜三个字的词(如“高性能”)靠两个重叠二元词(“高性”+“性能”)勉强覆盖,但精度和召回都有限——这不是参数能调出来的,是架构级限制。











