SQL 全文索引与 LIKE 查询优化

1次阅读

全文索引仅通过match() against()语法生效,不替代like;需匹配词干、避开停用词与短词限制;自然语言模式重相关性,布尔模式重逻辑控制;重建索引须显式操作且验证结果。

SQL 全文索引与 LIKE 查询优化

全文索引比 LIKE 快,但只在特定场景生效

mysqlFULLTEXT 索引确实能显著加速文本搜索,但它和 LIKE '%keyword%' 根本不是一回事——前者只对词干匹配、支持自然语言或布尔模式,后者是纯字符通配。如果你直接把 LIKE 查询换成加了全文索引的表,却没改写 SQL,性能不会变,甚至可能更慢。

常见错误现象:select * FROM articles WHERE content LIKE '%redis%'; 即使 content 建了 FULLTEXT,这条语句依然走全表扫描,索引完全不触发。

  • 必须改用 MATCH() AGAINST() 语法才能走全文索引,例如:MATCH(content) AGAINST('redis' IN NATURAL LANGUAGE MODE)
  • LIKE 中带前导通配符('%xxx''%xxx%')时,B+ 树索引失效,全文索引也救不了——它不处理子串匹配
  • 全文索引默认忽略停用词(如 “the”、“is”)、长度小于 4 的词(MySQL 5.7+ 默认 ft_min_word_len=4),搜 “go” 或 “AI” 可能查不到

IN NATURAL LANGUAGE MODE 和 IN Boolean MODE 怎么选

两种模式底层都走全文索引,但语义和行为差异极大,选错会导致结果漏掉或误召。

使用场景:NATURAL LANGUAGE MODE 适合用户搜索框这类“大概找找”的场景;BOOLEAN MODE 更像高级过滤,适合后台管理或需要精确控制逻辑的接口

  • NATURAL LANGUAGE MODE 自动计算相关性得分(RELEVANCE),返回结果按 MATCH() AGAINST() 得分降序,但不支持 +-* 等操作符
  • BOOLEAN MODE 不算相关性,只做逻辑匹配,支持 +word(必须含)、-word(必须不含)、word*(前缀匹配),但需注意:+ 和 – 前不能有空格,AGAINST('+redis -cache' IN BOOLEAN MODE) 合法,AGAINST('+ redis') 报错
  • 短词问题在 BOOLEAN MODE 下更明显:即使调小 ft_min_word_len,重建索引后也要执行 OPTIMIZE table tbl_name 才生效

LIKE 查询真没法优化?这些替代方案更实际

如果业务强依赖 LIKE '%xxx%'(比如日志关键词高亮、模糊字段补全),硬上全文索引反而绕路。这时候该考虑更贴近需求的解法。

  • 前缀匹配(LIKE 'abc%')可以直接用普通 B+ 树索引,确保字段有索引且查询不带前导 %
  • 固定长度后缀(如文件扩展名)可逆存储:存 name_rev 字段(gnirtsString),再用 LIKE 'tsr%' 查后缀,配合索引有效
  • 高频模糊字段可冗余生成 n-gram(如 bi-gram)列,用等值查询代替模糊:把 “hello” 拆成 he, el, ll, lo,建索引查 gram = 'el',适合中低频更新场景
  • 真正海量文本(GB+)且模糊要求高,别死磕 MySQL——ES 或 sqlite FTS5 是更合理的选择,MySQL 全文索引不是通用搜索引擎

重建全文索引时容易被忽略的三件事

改了 ft_min_word_len 或加了新字段后,很多人只执行 ALTER TABLE ... ADD FULLTEXT 就以为完事,结果搜不到刚设的短词,或者旧数据不生效。

  • 全文索引不是动态更新的:新增配置后,必须重建索引,命令是 ALTER TABLE tbl_name DROP INDEX ft_idx; ALTER TABLE tbl_name ADD FULLTEXT ft_idx(col);,单条 ADD 不会重新解析历史数据
  • MyISAM 表支持 REPAIR TABLE tbl_name QUICK 加速重建,InnoDB 只能靠 OPTIMIZE TABLE,期间表锁,线上慎用
  • 确认是否生效,别只看 SHOW INDEX:运行 SELECT MATCH(content) AGAINST('test' IN NATURAL LANGUAGE MODE) FROM tbl LIMIT 1;,返回非 0 才说明索引参与了计算

全文索引不是开关一开就全局生效的魔法,它高度依赖查询写法、配置同步、数据重载三个环节。少一个,就回到 LIKE 的原始速度。

text=ZqhQzanResources