MySQL 中的全文索引实现原理与使用限制

在数据库面试中,MySQL 的全文索引(Full-Text Index)是一个高频考点。很多候选人对 LIKE '%keyword%' 的低效深有体会,也能说出全文索引可以加速模糊匹配,但当面试官追问“全文索引底层是怎么实现的”“为什么中文分词需要 ngram”“为什么全文索引有那么多使用限制”时,能系统回答的人并不多。本文从数据结构、检索流程、分词机制到使用限制,系统梳理 MySQL 全文索引的核心知识。

一、为什么需要全文索引

假设有一张文章表 articles,包含 titlebody 两个文本字段。如果使用 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_TABLEINNODB_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') 时,大致流程是:

  1. 对查询词做同样的分词和停用词过滤;
  2. 在倒排索引中查找每个词对应的文档 ID 列表;
  3. 根据 IN NATURAL LANGUAGE MODEIN BOOLEAN MODE 计算相关性得分(relevance);
  4. 按得分排序返回结果。

IN NATURAL LANGUAGE MODE 会计算 TF-IDF 类似的权重,词频越高、出现文档越少,得分越高;IN BOOLEAN MODE 则支持 +(必须包含)、-(必须排除)、*(通配)等操作符。

四、MyISAM 与 InnoDB 的差异

早期只有 MyISAM 支持全文索引,其实现相对简单,直接在 .MYI 文件中维护倒排表。InnoDB 从 MySQL 5.6 开始支持全文索引,但实现更复杂:

  • MyISAM 支持在内存中缓存索引,重启后需要重建;
  • InnoDB 使用辅助表持久化,支持事务和崩溃恢复;
  • InnoDB 的全文索引在删除和更新时会产生“碎片”,需要定期 OPTIMIZE TABLE 清理。

面试中如果被问到“为什么 InnoDB 全文索引比 MyISAM 慢”,可以从辅助表维护、事务一致性、合并开销等角度回答。

五、使用限制与注意事项

全文索引虽然强大,但限制非常多,这也是面试常考的点:

  1. 字段类型限制:只能建在 CHARVARCHARTEXT 及其变体上,不能建在 INTDATE 等类型上。
  2. 最小词长限制:小于 innodb_ft_min_token_size(默认 3)的词不会被索引,中文场景需要配合 ngram 调整。
  3. 停用词限制:常见词被过滤,查询时可能“查不到”。
  4. 中文分词问题:默认分词器不支持中文,必须使用 WITH PARSER ngram,且 ngram 会产生大量冗余 token,索引体积膨胀。
  5. 无法使用 B+Tree 的部分匹配:全文索引只支持整词或前缀(*)匹配,不支持 LIKE '%中间%' 这种任意位置匹配。
  6. 更新代价高:每次 INSERT/UPDATE/DELETE 都要维护倒排表,写入性能下降明显。
  7. 查询结果可能延迟:受 FTS Index Cache 影响,刚写入的数据可能查不到。
  8. 不能用于 JOIN 的 ON 条件MATCH ... AGAINST 只能出现在 WHERESELECT 中,不能作为连接条件。
  9. 布尔模式下的操作符+-*" 等有特殊含义,需要转义或注意语义。
  10. 索引体积大:倒排表通常比原数据大很多,需要预留磁盘空间。

六、面试答题思路总结

当被问到“MySQL 全文索引的实现原理与限制”时,可以按以下结构回答:

  • 原理:倒排索引(词 → 文档ID),InnoDB 通过 FTS 辅助表持久化,内存缓存 + 批量合并;
  • 分词:默认按空格标点切分,中文用 ngram,受停用词和最小词长影响;
  • 检索:MATCH AGAINST,支持自然语言和布尔两种模式,计算相关性得分;
  • 限制:字段类型、最小词长、停用词、中文分词、写入代价、结果延迟、索引体积等。

掌握这些点,既能回答“是什么”,也能解释“为什么”,在面试中就能体现出对 MySQL 底层机制的深入理解。

未经允许不得转载:任鹏个人博客 » MySQL 中的全文索引实现原理与使用限制

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏