MyISAM全文索引必须显式创建,否则MATCH()报错1191;仅支持空格/标点分词,中文需ngram或Elasticsearch;50%阈值和内置停用词导致静默失败。

MyISAM 全文索引必须显式创建,不能靠 MATCH() 自动触发
没建 FULLTEXT 索引就写 MATCH(title) AGAINST('xxx'),MySQL 会直接报错:Error 1191: Can't find FULLTEXT index matching the column list。这不是语法错误,是底层机制限制——MyISAM 的全文检索完全依赖索引结构,没有索引就没有倒排表,MATCH 就无从查起。
实操建议:
- 建表时直接定义:
CREATE TABLE articles (id INT, title VARCHAR(255), content TEXT, FULLTEXT(title, content)) ENGINE=MyISAM; - 已有表添加索引:
ALTER TABLE articles ADD FULLTEXT(title, content);(注意:MyISAM 建索引过程会锁表,大数据量时慎选业务高峰期) - 确认索引是否生效:
SHOW INDEX FROM articles WHERE Key_name = 'ft_title_content';或查INFORMATION_SCHEMA.STATISTICS
AGAINST 支持三种模式,但 MyISAM 对 BOOLEAN MODE 更友好
MyISAM 默认用自然语言模式(NATURAL LANGUAGE MODE),它会自动过滤停用词、忽略短词(ft_min_word_len 默认为 4)、并对结果按相关性排序。但实际业务中,你往往需要精确控制逻辑,比如“必须含‘MySQL’且不含‘tutorial’”,这就得用布尔模式。
常见陷阱:
- 漏写
IN BOOLEAN MODE:写成AGAINST('+mysql -tutorial')不生效,必须是AGAINST('+mysql -tutorial' IN BOOLEAN MODE) - 自然语言模式下
+和-被当普通字符处理,不是操作符 - 布尔模式不计算相关性分值,
MATCH() AGAINST()返回的是 0/1,不能用于ORDER BY score
MyISAM 原生分词只认空格和标点,中文基本不可用
MyISAM 的分词器对中文完全无感。它不会把“数据库优化”切分成“数据库”“优化”,而是当成一个超长字符串;如果字段里存的是连续汉字(如 content = '数据库优化是关键'),默认分词后只剩单字或空 token,MATCH 必然返回空。
想让中文“勉强可用”,只能改配置,但效果有限:
- 调小
ft_min_word_len = 2(需重启 MySQL,且影响所有表) - 换字符集为
gbk或gb2312,配合自定义停用词表(ft_stopword_file) - 手动在内容里加空格分隔关键词(如存成
'数据库 优化 性能'),但这违背数据一致性原则
真正靠谱的方案是:别用 MyISAM 做中文全文检索。要么上 ngram 插件(仅 InnoDB 支持),要么换 Elasticsearch / Sphinx。
50% 阈值和停用词是静默失败的主因
MyISAM 有个硬规则:如果一个词在超过 50% 的行中出现,它会被自动当作“无效词”排除——哪怕你搜的是“MySQL”,而全表 60% 的文章标题都带这个词,MATCH 也会返回空。这不是 bug,是设计,目的是避免高频词污染结果。
验证方法很直接:
- 先查该词实际覆盖率:
SELECT COUNT(*) FROM articles WHERE content LIKE '%MySQL%'; - 再试布尔模式绕过阈值:
WHERE MATCH(title) AGAINST('MySQL' IN BOOLEAN MODE)(布尔模式不触发 50% 过滤) - 检查停用词:
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD;(MyISAM 用的是内置静态表,无法动态查,只能翻文档或试搜常见虚词)
最常被忽略的一点:MyISAM 的停用词表是编译进引擎的,不能删不能改,连“的”“了”“是”这种中文虚词都在里面。搜单字或虚词,基本注定为空——这不是配置问题,是能力边界。


















