全文索引不会被优化器“自动选中” 很多朋友在优化MySQL查询时,可能会发现一个“奇怪”的现象:明明给表加上了FULLTEXT索引,但执行EXPLAIN时,key列却总是显示NULL。这其实不是索引失效,而是MySQL优化器的一个特殊设计。简单来说,全文索引不会被当作普通B+树索引那样,自动参与查询
很多朋友在优化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 content或GROUP BY content这样的操作,即使列上有全文索引,也完全用不上。
全文索引的核心在于“分词”,而这个关键步骤发生在存储引擎层,与上层的SQL解析器是分开的。对于中文、日文这类没有天然空格分隔的语言,默认的分词器是无效的,必须显式指定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_0000000000000123_0000000000000124_INDEX_1),这些表对用户不可见,也不会在EXPLAIN中展示。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这两个字段没有合适的索引来覆盖,那么全文索引带来的速度提升,很可能就浪费在后续的逐行过滤上了。
IN BOOLEAN MODE)支持使用+(必须包含)、-(必须不包含)、*(通配符)等操作符,能更精确地控制匹配范围,提前排除大量无关文档,有时比自然语言模式效率更高。RELEVANCE)排序,即使用ORDER BY MATCH(...) AGAINST(...),也会触发文件排序(Using filesort),这是无法用索引优化的。InnoDB的全文索引更新是异步进行的。当你执行INSERT或UPDATE后,变更并不会立刻写入倒排索引,而是先进入一个叫FTS insert buffer的缓冲区,由后台线程定期合并。DELETE操作也不会立即清理数据,而是标记到DELETED辅助表。时间一长,索引内部就会产生碎片,导致查询效率下降。
遗憾的是,没有一条像OPTIMIZE TABLE那样能直接整理全文索引碎片的简单命令。常见的维护手段包括:
OPTIMIZE TABLE articles。这会重建整张表及其所有索引(包括全文索引),效果彻底,但需要锁表,耗时较长,对线上业务影响大。INFORMATION_SCHEMA.INNODB_FT_CONFIG系统表中的optimize_count值,可以监控后台合并线程的进度。如果这个值持续增长,说明索引合并已经滞后于数据更新了。还有一个更根本的麻烦:一旦创建了全文索引,就无法修改其分词器类型或字段组合。任何这类调整,都只能先删除索引,再重新创建。而在重建期间,新写入的数据可能无法被正确分词,从而导致短暂的搜索不一致。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述