fulltext索引通过倒排索引实现o(log n)文本搜索,而like需全表扫描;要求字段类型合规、引擎支持(推荐innodb)、显式建索引、合理配置ft_min_word_len与停用词,并注意中文分词及布尔模式安全。

直接建 FULLTEXT 索引 + 用 MATCH() AGAINST() 查询,就能跳过全表扫描,把文本搜索从 O(n) 降为接近 O(log n)。前提是字段类型合规、引擎支持、配置没卡死。
为什么 LIKE '%keyword%' 慢得像卡住,而 FULLTEXT 能快十倍?
LIKE 是逐行读取整个 TEXT 字段做字符串匹配,哪怕只搜一个词,也要把每条记录的全文内容加载进内存比对;FULLTEXT 则提前把文本分词、去停用词、建倒排索引——查“mysql”时,数据库直接定位到所有含该词的行 ID,不碰原始文本。
- MyISAM 和 InnoDB 都支持,但新项目一律用
InnoDB(事务安全、崩溃可恢复) - 字段必须是
CHAR/VARCHAR/TEXT类型,JSON或BLOB不行 - 建索引语句要显式写:
ALTER TABLE articles ADD FULLTEXT(title, content),不能靠隐式优化 - 如果表已有上百万数据,建索引过程会锁表(InnoDB 5.6+ 支持在线 DDL,但默认仍可能阻塞写入)
ft_min_word_len 设太小,反而让全文索引变重又慢
默认值 ft_min_word_len=4,意味着 “go”、“AI”、“PHP” 这类短词根本不会被收录进索引——你搜了也白搜。但盲目调成 1 或 2,会导致索引体积暴涨、分词爆炸、查询响应变长。
- 中文场景慎用:MySQL 原生不支持中文分词,单字索引意义极低,建议先用外部工具预处理(如结巴分词后存入分词字段)
- 改配置必须重启 MySQL 或执行
SET GLOBAL ft_min_word_len = 2,然后 重建全文索引 才生效(OPTIMIZE TABLE不够) - 停用词同样影响大:
ft_stopword_file可指定自定义停用词表,避免“的”“是”“一个”占满索引空间
IN BOOLEAN MODE 下传参不洁,会直接报错或漏结果
AGAINST('+php -mysql' IN BOOLEAN MODE) 看似灵活,但用户输入若带 +、-、~、>、,不经清洗就拼进 SQL,轻则语法错误(ERROR 1064),重则逻辑反转(本想搜“php”,结果变成“必须不含 php”)。
- 存储过程中不能用变量替换列名:
MATCH(@col_name) AGAINST(...)会报错,列名必须字面量写死 - 动态关键词建议用
CONCAT()+ 白名单过滤:只保留字母、数字、空格、引号,删掉所有布尔操作符 - 自然语言模式(默认)返回相关性分数,适合排序;布尔模式不返回分数,但支持精确控制,别混用
- 不要在
MATCH()外再套WHERE ... LIKE,那等于放弃全文索引,又回退到扫全表
真正卡住性能的,往往不是索引有没有,而是索引建在哪、怎么查、以及查的时候有没有悄悄绕过它——比如加了个 WHERE status = 1 AND MATCH(...) AGAINST(...),但 status 没索引,MySQL 就可能先扫 status 再对结果集做全文匹配,白搭。











