全文索引不会被优化器“自动选中”
许多开发者在优化MySQL查询性能时,常会遇到一个令人困惑的现象:已经为数据表添加了FULLTEXT全文索引,但执行EXPLAIN分析查询计划时,key列却始终显示为NULL。这并非索引失效,而是MySQL优化器的一项特殊机制。本质上,全文索引不会被纳入常规的B+树索引成本评估体系。它更像一个需要特定“指令”才能激活的专属搜索工具。
这个核心“指令”就是MATCH ... AGAINST语法。如果查询语句仍使用WHERE content LIKE '%关键词%'这样的模糊匹配,优化器将完全忽略全文索引,转而进行全表扫描或使用其他可用的普通索引。
- 激活条件:必须使用
MATCH(column) AGAINST('keyword')语法才能启用全文索引检索。 - 搜索模式:
AGAINST函数的第二个参数决定了搜索行为,包括默认的自然语言模式(IN NATURAL LANGUAGE MODE)、支持高级运算符的布尔模式(IN BOOLEAN MODE),以及能进行语义扩展的查询扩展模式(WITH QUERY EXPANSION)。 - 功能限制:需要特别注意,全文索引无法用于加速排序(
ORDER BY)或分组(GROUP BY)操作。即使相关列已建立全文索引,这些查询依然无法从中获益。

全文索引的词法分析由分词器控制,不是 SQL 层逻辑
全文索引的核心在于“分词”,这一关键步骤由存储引擎层的分词器完成,独立于上层的SQL解析逻辑。对于中文、日文等无天然空格分隔的语言,MySQL默认的分词器无法有效工作,必须显式指定ngram解析器。
ALTER TABLE articles ADD FULLTEXT INDEX ft_title_content (title, content) WITH PARSER ngram;
如果在创建索引时遗漏了WITH PARSER ngram子句,对中文字段进行全文搜索很可能返回空结果。因为默认分词器会尝试按空格和标点切分,而一个连续的中文句子会被视为一个超长“单词”,导致匹配失败。
- 分词粒度:
ngram_token_size参数控制中文分词的精细度,默认值为2(按双字切分)。可调整为1(单字)或3(三字),但粒度越小,生成的索引体积越大,存储开销越高。 - 内部存储:分词后的结果存储在内部的FTS(全文搜索)辅助表中(表名格式如
FTS_0000000000000123_0000000000000124_INDEX_1),这些表对用户透明,也不会在EXPLAIN输出中显示。 - 引擎区别:MyISAM引擎采用另一套全文索引实现,且不支持
ngram解析器。在进行跨存储引擎的数据迁移时,全文搜索的行为和结果可能发生显著变化。
全文查询性能瓶颈常不在索引本身,而在匹配后过滤
使用MATCH ... AGAINST确实能高效定位相关文档ID并计算相关性得分,但性能瓶颈往往出现在后续步骤。如果查询还包含其他复杂的WHERE过滤条件或JOIN操作,MySQL可能需要先获取所有匹配的文档ID,再回到主表中逐行校验这些附加条件。此过程若涉及大量随机磁盘I/O,全文索引带来的性能优势将迅速被抵消。
以下是一个典型场景:
SELECT * FROM articles WHERE MATCH(title, content) AGAINST('数据库优化' IN NATURAL LANGUAGE MODE)
AND status = 'published'
AND create_time > '2025-01-01';
在此查询中,如果status和create_time字段缺乏有效的辅助索引,那么全文索引带来的快速检索收益,很可能消耗在后续对大量中间结果的行级过滤上。
- 优化方案:建议为高频使用的过滤条件单独建立索引。需注意,InnoDB存储引擎不支持在同一组合索引中混合全文索引列和普通列。
- 模式影响:布尔模式(
IN BOOLEAN MODE)支持使用+(必须包含)、-(必须排除)、*(前缀通配符)等运算符,能更精确地限定匹配范围,提前过滤无关文档,有时比自然语言模式效率更高。 - 排序开销:若需按相关性评分排序(如
ORDER BY MATCH(...) AGAINST(...) DESC),即使使用了全文索引,该操作也会触发文件排序(Using filesort),无法通过索引优化。
全文索引重建与碎片问题容易被忽略
InnoDB引擎的全文索引更新采用异步机制。执行INSERT或UPDATE操作后,数据变更不会立即同步到倒排索引,而是先进入名为FTS insert buffer的缓冲区,由后台线程定期合并。DELETE操作也仅是在DELETED辅助表中进行标记,而非物理删除。长期运行后,索引内部会产生碎片,导致查询性能逐渐下降。
遗憾的是,MySQL没有提供类似OPTIMIZE TABLE那样可直接整理全文索引碎片的简单命令。常见的维护方法包括:
- 全表优化:执行
OPTIMIZE TABLE articles。此操作会重建整张表及其所有索引(含全文索引),效果彻底,但需要锁表,耗时较长,对线上服务影响显著。 - 手动流程:在业务低谷期,采用数据导出→删除全文索引→重建表结构→导入数据→重新创建全文索引的步骤。过程虽繁琐,但可控性更强。
- 监控指标:通过查询
INFORMATION_SCHEMA.INNODB_FT_CONFIG系统表中的optimize_count值,可以监控后台合并线程的进度。若该值持续增长,表明索引合并速度已滞后于数据更新。
另一个根本性限制是:全文索引一旦创建,其分词器类型和字段组合便无法修改。任何此类调整都必须先删除原索引,再重新创建。在重建期间,新写入的数据可能无法被正确分词,从而导致短暂的搜索不一致性问题。
