索引基础:B+树、哈希、全文索引
我记得刚接触数据库时,觉得索引就是个黑盒子。
慢查询就加索引,加完快了就完事。
后来被线上事故狠狠教训过——选错索引类型,直接拖垮了整个库。
今天我就把这三种核心索引掰开揉碎讲清楚。你自己想想看,连底层都不摸清,调优就是瞎蒙。
B+树索引——绝大多数场景的默认选择
B+树,说白了就是个平衡的多路搜索树。
跟普通二叉树不同,B+树的节点可以存几百个键值。树的高度通常只有3-4层。这意味着什么?你查3-4次磁盘I/O就能找到任何一行数据。
一个常见误区:很多人以为聚簇索引和非聚簇索引是两种索引类型。其实它们都是B+树,只是叶子节点存的东西不一样。
| 特性 | 聚簇索引 | 非聚簇索引(二级索引) |
|---|---|---|
| 叶子节点内容 | 整行数据 | 主键值 + 索引列 |
| 表组织方式 | 索引即数据 | 独立于数据 |
| 回表查询 | 不需要 | 需要二次查找 |
| 每表最多 | 1个 | 多个 |
哈希索引——等值查询的闪电战
哈希索引的原理简单粗暴:把键值通过哈希函数映射到固定位置的桶里。
等值查询,O(1)复杂度。比B+树的O(log n)快了一个量级。
但缺点也很致命:
- 不支持范围查询——哈希函数破坏了键的顺序性
- 不支持部分匹配——比如like 'abc%'直接凉凉
- 不支持排序——ORDER BY对哈希索引完全无效
- 哈希冲突——大量冲突时性能骤降
我记得之前在项目里遇到过一个问题:业务方把某个自增ID字段建成了哈希索引。
等值查询确实快到飞起。
但后来加了分页排序功能,那个查询瞬间变成全表扫描。
嗯,这就是典型的索引类型选型失误。
自适应哈希索引——MySQL的自动优化
InnoDB有一个隐藏的宝藏:自适应哈希索引(AHI)。
它会在运行时自动监控二级索引的访问模式。如果发现某些页频繁被等值查询命中,InnoDB会自动在内存中为这些页构建哈希索引。
这个过程完全无感。开发者不需要做任何配置。
但要注意:
- AHI只存在于内存,重启后清空
- 如果表上有大量无规律的等值查询,AHI可能会占用太多内存
- 极端情况下,AHI管理锁争用反而会成为瓶颈
全文索引——文本搜索的专属武器
全文索引跟B+树、哈希完全不同。它不是基于键值映射,而是基于倒排索引。
简单说,它的原理是:
- 把文本分词,拆成一个个单词
- 建立单词→文档ID的映射表
- 搜索时会匹配分词后的结果
为什么要单独搞一套?你用B+树做like '%keyword%'试试。走不了索引,全表扫描,慢得要命。
全文索引专门解决这个问题。
使用场景:
- 文章内容的模糊搜索
- 日志关键词匹配
- 商品描述的快速检索
注意事项:
- MySQL的全文索引只支持MyISAM和InnoDB(5.6+)
- 中文分词依赖插件(ngram或jieba)
- 全文索引维护成本高,不适合写频繁的表
三类索引总结对比
| 维度 | B+树索引 | 哈希索引 | 全文索引 |
|---|---|---|---|
| 数据结构 | 平衡多路搜索树 | 哈希表 | 倒排索引 |
| 等值查询 | O(log n) | O(1) | O(m),m为匹配文档数 |
| 范围查询 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 |
| 排序 | ✅ 支持 | ❌ 不支持 | ❌ 不支持 |
| 模糊匹配 | 仅前缀匹配 | 不支持 | 分词匹配 |
| 磁盘占用 | 中 | 小 | 大 |
| 适用场景 | 通用场景,90%的查询 | 高并发等值查询 | 文本内容搜索 |
等值高频用哈希,
范围排序B+树,
文本搜索上全文,
选错类型后悔哭。
一个实战案例
之前我接手过一个订单系统。订单表有500万数据,经常需要查某个用户最近30天的订单。
原始SQL:
SELECT * FROM orders
WHERE user_id = 12345
AND create_time BETWEEN '2024-01-01' AND '2024-01-31'
ORDER BY create_time DESC;
原先是单列索引在user_id上。每次查询都要过滤大量时间数据,回表次数爆炸。
我的优化方案:
- 改成联合索引:(user_id, create_time)
- 利用B+树的顺序性——索引内时间已经是排序好的
- 避免回表——如果只查索引列,可以走覆盖索引
改完之后,查询时间从1.2秒降到了8毫秒。嗯,你没看错,就是这么夸张。
这就是我为什么一直强调:索引类型选对只是第一步,真正的高手,会把索引结构和查询模式匹配到极致。