作者:程序员平
原文链接:mp.weixin.qq.com/s/iAMioA1bs...
在数据库应用中,文本搜索是一类常见但性能挑战极大的需求。尤其在实际业务场景中,我们经常会遇到这样的情况:当数据规模增长到百万级甚至更大时,使用 LIKE '%关键词%'
进行模糊查询,查询响应时间往往会从毫秒级骤升到数秒甚至更久。为了优化性能,我们可能会尝试将模糊匹配范围限制在字符串的开头或结尾,比如使用 LIKE '关键词%'
或 LIKE '%关键词'
。
尽管在某些情况下,这些方式能够部分利用索引(如前缀匹配能用上 B-Tree 索引),但一旦查询条件仍包含通配符 %
在前部位置(如 %关键词
或 %关键词%
),就彻底失去了索引加速效果,只能进行全表扫描。
随着数据量的不断增长,这类模糊查询的性能会呈指数级下滑,严重影响系统的响应能力与扩展性。在文章系统、日志检索、评论搜索等文本密集型场景中尤为突出,成为性能瓶颈的高发点。
一、什么是 FULLTEXT 索引?
FULLTEXT 是 MySQL 提供的一种专用于 全文检索(Full-Text Search) 的索引类型,适用于 CHAR、VARCHAR 和 TEXT 字段。它能够高效地在文本中查找关键字组合,而不是简单的子串匹配。自 MySQL 5.6 起,InnoDB 引擎也开始支持 FULLTEXT 索引(此前仅 MyISAM 支持)。
FULLTEXT 索引的核心优势
为什么 FULLTEXT 比 LIKE 快?根本原因在于它的底层设计专为文本搜索而生。
- 为文本搜索优化设计
-
- 不像 B-Tree 索引主要用于精确值匹配或区间查找,FULLTEXT 索引面向的就是非结构化数据中的词汇匹配。
- 使用倒排索引结构(Inverted Index)
-
- 将关键词映射到文档 ID,而不是文档映射到词,大幅提升搜索效率。
- 智能分词机制
-
- 自动将长文本拆解为有意义的"词",不仅限于字符匹配,为查询提供更精准的粒度。
- 支持相关性评分与排序
-
- 查询结果不再只是"是否命中",而是按照与搜索词的相关度打分排序。
- 支持复杂的搜索语法
-
- 包括布尔搜索(AND/OR/NOT)、短语匹配、模糊匹配等,用法接近搜索引擎的体验。
FULLTEXT 索引的底层架构
要真正理解为什么 FULLTEXT 索引在处理文本搜索时能如此高效,我们就需要深入到它的底层结构来看看它究竟做了什么。
我们知道,普通的 B-Tree 索引是为结构化数据(比如 ID、时间、价格)而设计的。而 FULLTEXT 索引处理的是非结构化文本 ------ 也就是文章、评论、内容字段等等。这类字段没法用传统的"左匹配"或"范围查找"去优化,所以 MySQL 引入了一种全新的索引机制:倒排索引(Inverted Index)。
🧠 什么是倒排索引?
倒排索引最早源于搜索引擎领域,它的核心思想是:
与其记录"每篇文章包含哪些词",不如反过来记录"每个词在哪些文章中出现过"。
✅ 举个栗子
假设我们有以下几篇文章:文档1:MySQL 是一个全文搜索数据库文档2:数据库性能优化是关键文档3:索引可以提升查询效率
如果用"正排索引"的思路,我们会得到:

而倒排索引会记录成这样:

这种方式有什么好处?
当你要查"包含数据库的所有文章",只需要从"数据库"这个关键词入手,立刻知道它在哪些文档中出现;
不需要扫描每一行文本;
查询复杂度从 O(n) 降到接近 O(1)。
这正是倒排索引的核心价值 ------ 将查词变成了查表,极大降低了搜索成本。
FULLTEXT 关键组件
为了实现上述倒排逻辑,FULLTEXT 索引在 InnoDB 引擎中构建了如下组件:
组件 | 作用描述 |
---|---|
倒排索引表 | 存储每个词对应的文档列表(posting list),是 FULLTEXT 索引的核心结构 |
分词器(Tokenization) | 按语言规则拆解文本内容;英文支持良好,中文需借助插件如 Mroonga、Jieba |
词频统计(TF)与文档频率(DF) | 用于计算关键词在文档中的重要程度,驱动相关性评分 |
删除/更新标记机制 | 避免频繁重建索引,采用懒处理策略管理文档生命周期 |
内部文档ID映射 | 将实际记录与逻辑倒排索引进行关联,提高处理效率 |
FULLTEXT 索引的工作流程
索引创建过程
当为一个表列创建FULLTEXT索引时,MySQL会执行以下操作:

查询执行过程
二、 性能对比:FULLTEXT vs LIKE
为了直观展示FULLTEXT索引的性能优势,我们通过一个实际测试来比较:
创建测试表
sql
ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineCREATE TABLE IF NOT EXISTS articles ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) NOT NULL, content TEXT NOT NULL, author VARCHAR(100), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FULLTEXT INDEX idx_ft_content (content)) ENGINE=InnoDB
- 测试环境
- 表:articles,包含100万条记录
- 列:content VARCHAR(2000),存储文章内容
- 测试查询:搜索包含"database optimization"的内容
LIKE查询
sql
SELECT COUNT(*) FROM articles WHERE content LIKE '%database optimization%'
FULLTEXT查询
sql
SELECT COUNT(*) FROM articles WHERE MATCH(content) AGAINST('database optimization' IN NATURAL LANGUAGE MODE)
对比结果
sql
LIKE查询:共找到94850条记录,耗时5.3568秒全文搜索:共找到94850条记录,耗时0.1337秒全文搜索比LIKE快40.1倍
注意事项
- 中文搜索效果差异
MySQL 的 FULLTEXT 索引对英文等空格分词语言支持良好,但对于中文这种连续文本没有空格分隔的语言,默认分词效果很差,可能导致:
sql
查询不到结果性能不如 LIKE 查询分词粒度不准确(如 "数据库优化" 被当作一个词)
- 推荐做法:
使用外部全文检索引擎(如 Elasticsearch 或 Sphinx)进行中文分词和检索;或在 MySQL 中使用支持中文分词的插件(如 Mroonga 或 Parser Plugin);若使用 MySQL 8.0+,也可以考虑配合 n-gram 分词器(ngram parser)支持中文。
- 字段类型限制
FULLTEXT 仅支持以下字段类型:CHAR、VARCHAR、TEXT。不能直接对 BLOB 类型使用全文索引。
三、 FULLTEXT 索引和普通索引有什么区别
核心区别概览
特性 | 普通索引(B-Tree) | FULLTEXT 索引(倒排索引) |
---|---|---|
底层结构 | B-Tree | 倒排索引(Inverted Index) |
适合的字段类型 | 数值、日期、短字符串、精确字段 | 文本字段(TEXT、VARCHAR) |
匹配方式 | 精确匹配、前缀匹配 | 关键词匹配、自然语言搜索 |
查询效率(精确查找) | 极高 | 不适合 |
查询效率(关键词搜索) | 较低(需要全表扫描) | 非常高 |
是否支持排序 | 支持 | 支持基于相关性排序(MATCH AGAINST) |
可否用于范围查找 | 可以,如 BETWEEN 、< 、> |
不可以 |
底层原理区别
- ✅ 普通索引(B-Tree):
-
- 将索引值按顺序构建一棵 B-Tree;
- 适合等值查找、范围查找;
- LIKE '前缀%' 可以利用索引(前缀匹配);
- LIKE '%关键词'、LIKE '%关键词%' 无法使用索引,会全表扫描。
- ✅ FULLTEXT 索引:
-
- 记录"词 → 出现在哪些文档(行)"的映射;
-
- 基于倒排索引(Inverted Index):
- 查询时先分词,然后查找包含这些词的行;
- 类似搜索引擎的原理,更适合自然语言文本。
查询效率对比
场景 | 普通索引效率 | FULLTEXT 效率 |
---|---|---|
查找 ID = 123 | 极快(O(log n)) | 不支持 |
查找 name LIKE 'zhang%' | 快(能用前缀索引) | 不推荐 |
查找 content LIKE '%日志%' | 慢(全表扫描) | 快(关键词匹配) |
查找文章包含"MySQL" | 慢(LIKE 低效) | 快(倒排索引) |
排序 | 支持索引排序 | 支持匹配度排序 |
能否"跟上"普通索引的效率?
在关键词搜索场景下,FULLTEXT 索引的性能远超普通索引。它能做到几毫秒内完成百万级文本的匹配,因为它事先构建了"关键词到行"的映射。
但在精确查找或排序/范围查询等结构化数据场景下,FULLTEXT 并不适用,这时候普通索引仍然是首选。
所以,FULLTEXT 并不是为了"取代"普通索引,而是用在完全不同的场景中:
- ✅ 结构化字段 → 普通索引(B-Tree)
- ✅ 非结构化文本 → FULLTEXT 索引
四、 总结****
MySQL的FULLTEXT索引为文本搜索提供了一种高效的解决方案,对于需要更高阶搜索功能的场景,可以考虑专业的搜索引擎如Elasticsearch,但对于大多数常规应用,合理使用的FULLTEXT索引已经能提供显著的性能提升和良好的用户体验。
希望这篇文章能够帮助你在实践中更好地应用。如果你有任何疑问或建议,欢迎在评论区留言讨论!