在数据库面试中,MySQL 的全文索引(Full-Text Index)是一个高频考点。很多候选人对 LIKE '%keyword%' 的低效深有体会,也能说出全文索引可以加速模糊匹配,但当面试官追问“全文索引底层是怎么实现的”“为什么中文分词需要 ngram”“为什么全文索引有那么多使用限制”时,能系统回答的人并不多。本文从数据结构、检索流程、分词机制到使用限制,系统梳理 MySQL 全文索引的核心知识。
一、为什么需要全文索引
假设有一张文章表 articles,包含 title 和 body 两个文本字段。如果使用 LIKE '%MySQL%' 查询,MySQL 必须对每一行进行全表扫描,逐字符匹配,无法使用 B+Tree 索引。当数据量达到百万级时,这种查询几乎不可用。
全文索引的目标就是:把文本内容拆分成词(token),建立“词 → 文档”的倒排映射,从而在查询时直接定位包含目标词的文档。这与 B+Tree 的“值 → 行”正排索引思路正好相反。
二、倒排索引的核心结构
全文索引的底层是倒排索引(Inverted Index)。可以把它理解为一张巨大的映射表:
关键词 文档ID列表
mysql → [1, 5, 12, 88]
database → [1, 3, 5]
index → [2, 5, 12]
在 InnoDB 中,这张映射表并不是以普通表的形式存储,而是通过一组特殊的辅助表(auxiliary tables)实现。创建全文索引时,InnoDB 会生成若干张以 FTS_ 开头的内部表,例如:
FTS_00000000000000xx_INDEX_1~INDEX_6:存储“词 → 文档”的倒排记录;FTS_..._DELETED:记录已删除但尚未清理的文档;FTS_..._BEING_DELETED:记录正在删除的文档。
这些表对用户不可见,但可以通过 information_schema.INNODB_FT_INDEX_TABLE、INNODB_FT_INDEX_CACHE 等系统表观察全文索引的内部状态。
三、InnoDB 全文索引的实现细节
1. 分词(Tokenization)
建立索引的第一步是把文本切分成词。InnoDB 使用**分词器(parser)**完成这一步:
- 默认分词器按空格和标点符号切分,只保留字母、数字等,且会统一转小写;
- 对于英文,这基本够用;对于中文,默认分词器会把一整句中文当成一个“词”,导致几乎无法检索;
- MySQL 5.7.6 起引入了 ngram 分词器,通过
ngram_token_size参数(默认 2)把中文按固定长度切分,例如“数据库”会被切成“数据”“据库”。
2. 停用词与最小词长
InnoDB 有两个重要参数:
innodb_ft_min_token_size(默认 3):长度小于该值的词不会被索引;innodb_ft_max_token_size(默认 84):超长词被截断或忽略;innodb_ft_server_stopword_table/innodb_ft_user_stopword_table:指定停用词表,像 “the”“a”“is” 这类无意义词不建立索引。
这意味着查询 LIKE '%ab%' 能匹配到,但全文索引可能因为词太短而查不到。
3. 索引的写入与合并
InnoDB 并不会每插入一行就立刻写入磁盘上的倒排表,而是先写入内存中的 FTS Index Cache。当缓存达到阈值或执行 OPTIMIZE TABLE 时,才会批量合并(merge)到磁盘辅助表。这种设计是为了避免频繁的随机写,但也带来一个后果:刚插入的数据可能暂时查不到,需要等待合并。
4. 检索流程
执行 MATCH(col) AGAINST('keyword') 时,大致流程是:
- 对查询词做同样的分词和停用词过滤;
- 在倒排索引中查找每个词对应的文档 ID 列表;
- 根据
IN NATURAL LANGUAGE MODE或IN BOOLEAN MODE计算相关性得分(relevance); - 按得分排序返回结果。
IN NATURAL LANGUAGE MODE 会计算 TF-IDF 类似的权重,词频越高、出现文档越少,得分越高;IN BOOLEAN MODE 则支持 +(必须包含)、-(必须排除)、*(通配)等操作符。
四、MyISAM 与 InnoDB 的差异
早期只有 MyISAM 支持全文索引,其实现相对简单,直接在 .MYI 文件中维护倒排表。InnoDB 从 MySQL 5.6 开始支持全文索引,但实现更复杂:
- MyISAM 支持在内存中缓存索引,重启后需要重建;
- InnoDB 使用辅助表持久化,支持事务和崩溃恢复;
- InnoDB 的全文索引在删除和更新时会产生“碎片”,需要定期
OPTIMIZE TABLE清理。
面试中如果被问到“为什么 InnoDB 全文索引比 MyISAM 慢”,可以从辅助表维护、事务一致性、合并开销等角度回答。
五、使用限制与注意事项
全文索引虽然强大,但限制非常多,这也是面试常考的点:
- 字段类型限制:只能建在
CHAR、VARCHAR、TEXT及其变体上,不能建在INT、DATE等类型上。 - 最小词长限制:小于
innodb_ft_min_token_size(默认 3)的词不会被索引,中文场景需要配合 ngram 调整。 - 停用词限制:常见词被过滤,查询时可能“查不到”。
- 中文分词问题:默认分词器不支持中文,必须使用
WITH PARSER ngram,且 ngram 会产生大量冗余 token,索引体积膨胀。 - 无法使用 B+Tree 的部分匹配:全文索引只支持整词或前缀(
*)匹配,不支持LIKE '%中间%'这种任意位置匹配。 - 更新代价高:每次 INSERT/UPDATE/DELETE 都要维护倒排表,写入性能下降明显。
- 查询结果可能延迟:受 FTS Index Cache 影响,刚写入的数据可能查不到。
- 不能用于 JOIN 的 ON 条件:
MATCH ... AGAINST只能出现在WHERE或SELECT中,不能作为连接条件。 - 布尔模式下的操作符:
+、-、*、"等有特殊含义,需要转义或注意语义。 - 索引体积大:倒排表通常比原数据大很多,需要预留磁盘空间。
六、面试答题思路总结
当被问到“MySQL 全文索引的实现原理与限制”时,可以按以下结构回答:
- 原理:倒排索引(词 → 文档ID),InnoDB 通过 FTS 辅助表持久化,内存缓存 + 批量合并;
- 分词:默认按空格标点切分,中文用 ngram,受停用词和最小词长影响;
- 检索:MATCH AGAINST,支持自然语言和布尔两种模式,计算相关性得分;
- 限制:字段类型、最小词长、停用词、中文分词、写入代价、结果延迟、索引体积等。
掌握这些点,既能回答“是什么”,也能解释“为什么”,在面试中就能体现出对 MySQL 底层机制的深入理解。
未经允许不得转载:任鹏个人博客 » MySQL 中的全文索引实现原理与使用限制

