MySQL索引深度解析:B+树、B树、哈希索引怎么选?
引言
在MySQL的性能优化中,索引绝对是最常用的手段之一!但面对B+树、B树、哈希索引这三种常见的索引结构,很多开发者却容易犯迷糊:它们有啥区别?什么时候该用谁?今天咱们就从底层原理到实际场景,一次性说透!
一、先搞懂:三种索引的核心结构差异
要理解它们的差异,得先看“底层长相”——就像盖楼,地基(结构)不同,功能(性能)自然天差地别。
1. B树:每个节点都带“仓库”的树
B树(平衡多路搜索树)是一种“自平衡”的树结构,最大的特点是每个节点(包括内部节点和叶子节点)都存了键值(Key)和对应的数据(Value)。
举个栗子🌰:假设B树的一个节点是16KB(MySQL默认磁盘块大小),如果存的是用户表的(id, name)数据,那这个节点可能同时存多个id和name的组合,就像一个“仓库”里既放索引又放货物。
2. B+树:仓库只存在叶子节点的“优化版B树”
B+树是B树的“亲儿子”,专门为磁盘存储优化。它的核心改进是:数据只存在叶子节点,内部节点只存键值(当“路标”)。
比如同样存(id, name),B+树的内部节点只存id的键值和子节点指针(类似字典的目录),所有真正的(id, name)数据都堆在叶子节点,而且叶子节点之间用双向指针连成一条“链子”。
3. 哈希索引:像字典目录一样“直给”
哈希索引的底层是哈希表,原理很简单:用哈希函数把键值(比如id=123)转成一个哈希值,然后把这个值作为“桶”的编号,直接存到对应的位置。
比如要查id=123的用户,先算哈希值(比如123%1000=233),然后直接去第233号桶里找数据——像极了字典的“拼音目录”,输入拼音直接翻到对应页码。
二、实战对比:等值查、范围查、排序查,谁更猛?
知道了结构,咱们再看实际查询场景下的表现——这才是选索引的关键!
1. 等值查询(=):哈希索引“理论上”最快?
- B树/B+树:需要从根节点开始一层一层往下找,时间复杂度是O(log n)。比如找id=100的用户,得先看根节点的键值,再进子节点,直到叶子节点找到数据。
- 哈希索引:直接算哈希值,定位到桶,时间复杂度O(1)(理想情况)。比如同样找id=100,哈希函数算出桶号,直接取数据。
但注意!哈希索引有个“坑”:如果数据量太大,哈希冲突(多个键值算到同一个桶)会很严重,这时候查询时间会退化成O(k)(k是桶里的链表长度),甚至比B+树还慢!
2. 范围查询(>、<、BETWEEN):B+树“吊打”全场!
- B树:叶子节点之间没链接,范围查询得从根节点重新遍历,效率极低。比如查age在20-30岁的用户,B树可能需要多次IO,慢得怀疑人生。
- B+树:叶子节点是双向链表,范围查询时只需要找到起始节点,然后顺着链表顺序扫描就行,时间复杂度O(log n + m)(m是结果数量)。比如查age在20-30岁,找到第一个age=20的节点,后面直接“顺藤摸瓜”拿数据。
- 哈希索引:完全不支持!哈希值是随机的,范围查询只能全表扫描,效率感人。
3. 排序查询(ORDER BY):B+树“天生的优势”
- B树:叶子节点无序,排序得把数据全读到内存再排序(文件排序),内存不够还得落盘,慢!
- B+树:叶子节点本身是有序链表,查询时直接按顺序扫描就能返回排序结果,无需额外操作。比如查age从大到小,B+树扫完链表就是降序结果。
- 哈希索引:哈希值无序,排序只能全表扫描后手动排序,同样慢。
三、空间和维护成本:省磁盘还是省时间?
1. 空间占用:B+树更“抠门”
- B树:每个节点都存数据,空间利用率低。比如一个16KB的节点,存10条数据可能就占满了,剩下的空间浪费。
- B+树:内部节点只存键值(不存数据),一个节点能塞更多键值,树更矮(比如同样16KB,能存100个键值而不是10个),磁盘IO次数更少。
- 哈希索引:哈希表需要预分配空间(负载因子0.7~0.8),存在空间浪费;冲突时链表变长,额外占内存。
2. 维护成本:B+树“省心”,哈希索引“麻烦”
- B树:插入/删除时要调整节点结构(分裂/合并),维护复杂度高。
- B+树:插入/删除主要发生在叶子节点,内部节点只调指针,维护简单;范围查询的有序性也让维护更高效。
- 哈希索引:数据量暴增时,哈希表可能触发扩容(重新哈希所有数据),可能导致数据库卡顿甚至锁表,维护成本极高。
四、MySQL里的“生存法则”:它们都在哪打工?
1. B+树:InnoDB的“顶梁柱”
InnoDB存储引擎的主键索引和二级索引,全!部!是!B+树!
- 主键索引(聚簇索引):叶子节点直接存整行数据,范围查询和排序效率拉满(比如
SELECT * FROM user WHERE age BETWEEN 20 AND 30 ORDER BY name
)。 - 二级索引:叶子节点存主键值(不是行指针),通过回表查聚簇索引获取完整数据(避免数据冗余)。
2. B树:MySQL里的“稀有动物”
主流数据库(包括MySQL)几乎不用纯B树做索引!因为内部节点存数据导致树高太高,磁盘IO次数多,早就被B+树取代了。
3. 哈希索引:Memory引擎的“配角”
MySQL的Memory引擎支持哈希索引(默认)和B+树索引,但生产环境很少用它存核心数据(数据非持久化,重启丢失)。哈希索引仅适合仅等值查询、数据量小、无排序需求的场景(比如临时缓存)。
五、总结:一张表+一个口诀,选索引不迷路!
特性 | B+树 | B树 | 哈希索引 |
---|---|---|---|
等值查询 | O(log n),高效 | O(log n),高效 | O(1)(理想),冲突时可能退化 |
范围查询 | O(log n + m),高效(有序链表) | O(n)(需重扫描),低效 | 不支持(全表扫描) |
排序查询(ORDER BY) | 直接支持(叶子节点有序) | 不支持(需额外排序) | 不支持(哈希值无序) |
空间利用率 | 高(内部节点无数据) | 低(内部节点存数据) | 中(预分配空间,冲突浪费) |
维护成本 | 低(仅调整叶子节点指针) | 高(节点分裂/合并复杂) | 高(扩容需重新哈希) |
MySQL典型场景 | InnoDB主键/二级索引 | 无(主流引擎不使用) | Memory引擎等值查询 |
选索引口诀:
需要范围查、排序 → 选B+树(InnoDB索引首选);
仅等值查、数据量小 → 选哈希索引(Memory临时场景);
B树?现在基本没它啥事儿啦!
最后提醒:实际开发中,90%以上的场景用B+树索引就够了!哈希索引别乱用,除非你明确知道业务只有等值查询且数据量小。记住:索引不是越多越好,合适的索引才是最好的!