MySQL全文检索必须先创建FULLTEXT索引,否则MATCH...AGAINST会报错或返回空;InnoDB要求MATCH列与索引列完全一致,MyISAM支持跨列匹配;中文需用ngram插件或额外分词处理。

MySQL 全文检索必须先建 FULLTEXT 索引
没加 FULLTEXT 索引,MATCH ... AGAINST 会直接报错或返回空结果,不是语法问题,是底层机制限制。InnoDB 和 MyISAM 都支持,但索引创建方式和行为有差异。
- MyISAM 对单列或多列建
FULLTEXT索引后,MATCH可跨列匹配;InnoDB 要求MATCH的列必须和索引定义的列完全一致(顺序、数量都不能差) - 中文需额外处理:MySQL 原生全文索引对中文不友好,分词靠空格或标点,没内置中文分词器。想搜“数据库优化”,得确保字段里真存着带空格的“数据库 优化”或者用 ngram 插件
- 建索引命令示例:
ALTER TABLE articles ADD FULLTEXT(title, content);—— 注意别漏掉表名和列名,也别在已有大量数据的表上直接建,可能锁表很久
MATCH/AGAINST 三种模式怎么选
AGAINST 后面不写模式默认是自然语言模式(NATURAL LANGUAGE MODE),但实际业务中常需要布尔模式或查询扩展模式,选错就搜不出东西。
- 自然语言模式适合普通关键词搜索,返回带相关性评分的行,但不支持通配符、+/- 操作符;
SELECT * FROM articles WHERE MATCH(title) AGAINST('mysql performance'); - 布尔模式支持逻辑操作:
+必含、-排除、*截断(如'perform*'匹配 perform / performance)、双引号短语匹配;必须显式声明:AGAINST('+mysql -tutorial' IN BOOLEAN MODE) - 查询扩展模式(
WITH QUERY EXPANSION)会自动把高频相关词加入搜索,容易放大噪声,比如搜“java”,可能混进“javascript”结果,慎用
为什么 MATCH 返回空,但 LIKE 能搜到
这不是 bug,是设计逻辑不同:MATCH 不是字符串模糊匹配,它依赖索引里的倒排结构 + 内置停用词表 + 最小词长限制。
- 默认停用词表包含常见虚词(如 “the”, “is”, “in”),长度小于 4 的英文词(可调)和所有中文单字基本被过滤,所以搜“a”、“我”、“的”肯定为空
- 字段值太短(比如只有 1–2 个词)或重复度过高(整列都是“test”),相关性评分低于阈值也会被过滤,
MATCH默认只返回评分 > 0 的行 - 验证方法:先查
MATCH(...) AGAINST(...)是否返回非零评分,再确认索引是否覆盖该列,最后看INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD或对应表确认停用词
性能和字符集踩坑点
全文检索慢?90% 是因为字符集或配置没对齐。尤其在 utf8mb4 下,ngram_token_size 设置不当会导致分词失效。
- InnoDB 的 ngram 分词器要求
ngram_token_size(默认 2)必须与建索引时一致;改了全局变量不影响已有索引,得重建 - 字段字符集要和表/库一致,混合使用
utf8和utf8mb4会导致索引无法命中,SHOW CREATE TABLE看一眼最省事 -
MATCH不能用在视图、临时表、分区表(InnoDB 分区表不支持 FULLTEXT)上,报错信息是ERROR 1214 (HY000): The used table type doesn't support FULLTEXT indexes,但实际不是表类型问题,是对象类型限制
真正麻烦的是中文场景下既要支持短词又要避免过度切分,ngram 和自定义分词服务之间得权衡——索引体积、更新延迟、查询精度,三者很难同时兼顾。










