为什么不是哈希表(Hash Table)?
**优点:**等值查询(SELECT * FROM table WHERE id=5)速度极快,时间复杂度O(1)
**淘汰理由:**不支持范围查询。哈希表里的数据是分散无序的,要执行WHERE id BETWEEN 1 AND 100这样的查询,哈希表只能全表扫描,无法按顺序查找
为什么不是二叉树/平衡二叉树(AVL)?
**优点:**查询时间复杂度稳定在O(logN)
**淘汰理由:**树太高,导致磁盘I/O次数太多
如果数据有100万条,AVL树的高度大约是20层。在数据库里,这意味查询一条数据最多可能需要20次磁盘I/O(每次读取一个节点)
一次磁盘I/O大约需要10ms,20次就是0.2s,对于单条查询这或许还能忍,但是面对高并发的线上系统,这绝对是灾难性的
为什么不是B树(B-Tree)?
B树已经是B+树的"前辈"了,它解决了二叉树"太高"的问题,因为他是多叉树,100万数据只需要3-4层
B树被淘汰的唯一原因,是B+树在"范围查询"和"磁盘I/O稳定性"上做得更好
**磁盘I/O不稳定:**B树的每个节点都存数据,导致一个16kB的磁盘页存不了几个索引,树变胖得不够彻底。B+树内部节点不存数据,能存上千个索引,树更"矮"
**范围查询需要回溯:**B树做范围查询时,在叶子节点找到数据后,要找下一个数据得回退到父节点,再进入下一个叶子节点。这个过程涉及频繁的磁盘I/O。而B+树的叶子节点用链表串起来了,找到起点后,只需要顺着链表顺序读取,完美契合磁盘的"预读"特性
为什么不是跳表(Skip List)或LSM树?
跳表(Redis选用):跳表是实现简单且性能不错的内存数据结构。但是它依赖随机指针跳跃,对磁盘不友好。并且它维护有序结构的成本比B+树
LSM树:LSM树是写优化的,它把随机写转化为顺序写,写入速度极快。但是MySQL InnoDB是读多写少的通用场景。LSM树的读取需要层层查找,且存在空间放大和读放大问题,不适合需要快速响应、稳定读延迟的在线事务场景
为什么B+树就适用于做MySQL的索引?
**极其"矮胖":**数据量再大,树高也稳定在2~4层。这意味着任何查询(无论是等值还是范围)都只需要极少的、且次数固定的磁盘I/O
**范围查询是"散步":**叶子节点上的双向链表,让范围遍历想在数组上移动一样自然高效,完全配合磁盘的预读机制
**写入性能稳定:**B+树的"分裂"和"合并"操作只涉及局部节点,不会像哈希表那样需要大规模重建
B+树对B树的三大核心优势
核心优势 具体说明 对数据库的意义 1. 更低的树高,更少的磁盘I/O B+树的非叶子节点只存索引,不存数据,每个磁盘页能容纳的索引数量远多于B树。 在同等数据量下,B+树的高度远低于B树,查询时需要的磁盘I/O次数更少,这是最主要的性能提升。 2. 更稳定的查询性能 B+树的所有数据都在叶子节点,任何查询都必须走到叶子节点才能找到数据。 查询的路径长度完全固定,不会出现B树那样有时快(数据在根节点)有时慢(数据在叶子节点)的情况,性能极度稳定可预测。 3. 极致高效的范围查询 B+树的所有叶子节点通过双向链表 串连,形成一个有序链表。B+树只要第一次走到了叶子节点,之后就可以在叶子节点之间直接横向移动进行查询,既不用退回上一级,更不用从头再找。 做范围查询(如 BETWEEN)时,找到起点后,只需沿着链表顺序扫描即可,完美利用磁盘预读特性。而B树需要反复回退到父节点,效率低下。