mysql全文索引仅支持myisam和innodb引擎,myisam支持布尔与自然语言模式,innodb 5.6+起支持但默认仅自然语言模式;必须用match() against()查询,中文需外部分词,短词和停用词需调优配置。

MySQL全文索引只能在MyISAM和InnoDB上用,但行为不同
MySQL原生全文搜索依赖 FULLTEXT 索引,不是所有引擎都支持——MyISAM 支持布尔模式和自然语言模式,InnoDB 从5.6起才支持,且默认只支持自然语言模式(不支持+/-等布尔语法),除非显式指定 WITH QUERY EXPANSION 或升级到8.0+并启用innodb_ft_enable_stopword等配置。
实操建议:
- 如果数据量小、更新不频繁,用
MyISAM更省心,ALTER TABLE t ADD FULLTEXT(title, content)即可建索引 - 若必须用
InnoDB(推荐),建表时就加索引:CREATE TABLE t (id INT, title TEXT, content TEXT, FULLTEXT(title, content)) ENGINE=InnoDB - 注意:
FULLTEXT索引列不能是TEXT以外的类型(比如VARCHAR(255)可以,但INT不行) - 建完索引后首次查询会慢,因为需要预热 ft cache;后续查询才快
MATCH() AGAINST() 是唯一能触发词频排序的语法
WHERE LIKE '%关键词%' 不统计频率,也不排序;只有 MATCH(col1, col2) AGAINST('关键词' IN NATURAL LANGUAGE MODE) 才按相关性(隐含词频+位置+字段权重)返回浮点数评分,并自动按该评分降序排列。
常见错误现象:
- 写成
AGAINST('关键词' IN BOOLEAN MODE)后发现结果没排序——布尔模式不返回分数,需手动加ORDER BY MATCH(...) AGAINST(...) - 查单字(如 'a'、'的')失败——MySQL默认停用词表会过滤掉这些,需修改
ft_stopword_file或设innodb_ft_enable_stopword=OFF(仅开发环境) - 中文直接搜会失效——MySQL原生全文索引不支持中文分词,必须先用外部工具(如
MeCab或应用层分词)把“搜索引擎”拆成“搜索”“引擎”再入库
IN NATURAL LANGUAGE MODE 的排序逻辑其实很朴素
它内部计算的是 TF-IDF 的简化版:词在当前文档中出现越多次(TF高),在整个表中越稀有(IDF高),得分就越高。但不会跨字段加权——MATCH(title, content) AGAINST('数据库') 中,title里出现1次和content里出现3次,后者得分更高。
性能与兼容性影响:
- 查询响应快(索引驱动),但建索引慢(全表扫描+倒排构建)
- 最小词长默认是4(
ft_min_word_len=4),搜“git”会命中不了,需改配置并重建索引 - 不区分大小写,但区分字符集——确保表、列、连接都用
utf8mb4_unicode_ci,否则可能漏匹配 - 无法做模糊前缀(如
search*),布尔模式支持'search*',但自然语言模式不支持
真正想按“关键词出现次数”精确排序?得绕开MATCH()
如果业务明确要求“谁包含‘MySQL’最多就排最前”,MATCH() AGAINST() 的TF-IDF反而干扰判断。这时应该用字符串函数硬算:
SELECT id, title,
(LENGTH(content) - LENGTH(REPLACE(content, 'MySQL', ''))) / LENGTH('MySQL') AS cnt
FROM t
WHERE content LIKE '%MySQL%'
ORDER BY cnt DESC;
但要注意:
- 这个公式对重叠词(如 'MySQLMySQL')会多算,实际应改用存储过程或应用层计数
- 没有索引加速,
LIKE '%...%'必然全表扫描,千万级数据会卡死 - 更稳的路是加一列
mysql_count TINYINT UNSIGNED DEFAULT 0,靠应用或触发器维护,查时直接ORDER BY mysql_count DESC
原生全文搜索看着简单,但中文、短词、精确频次这三块,MySQL都不打算替你兜底。要么接受它的规则,要么自己存频次。











