我们一起聊聊MySQL 索引的底层逻辑( 二 )


1.3 带有顺序访问指针的 B+Tree一般在数据库系统或文件系统中使用的 B+Tree 结构都在经典 B+Tree 的基础上进行了优化 , 增加了顺序访问指针 。

我们一起聊聊MySQL 索引的底层逻辑

文章插图
图片
如图所示,在 B+Tree 的每个叶子节点增加一个指向相邻叶子节点的指针,就形成了带有顺序访问指针的 B+Tree。做这个优化的目的是为了提高区间访问的性能,例如图中如果要查询 key 为从 18 到 49 的所有数据记录,当找到 18 后,只需顺着节点和指针顺序遍历就可以一次性访问到所有数据节点,极大提到了区间查询效率 。
1.4 为什么使用 B-Tree / B+Tree红黑树等数据结构也可以用来实现索引,但是文件系统及数据库系统普遍采用 B-/+Tree 作为索引结构,这一节将结合计算机组成原理相关知识讨论 B-/+Tree 作为索引的理论基础 。一般来说 , 索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上 。这样的话,索引查找过程中就要产生磁盘 I/O 消耗 , 相对于内存存?。?I/O 存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘 I/O 操作次数的渐进复杂度 。换句话说,索引的结构组织要尽量减少查找过程中磁盘 I/O 的存取次数 。下面先介绍内存和磁盘存取原理,然后再结合这些原理分析 B-/+Tree 作为索引的效率 。
主存存取原理目前计算机使用的主存基本都是随机读写存储器 ( RAM )  , 现代 RAM 的结构和存取原理比较复杂,这里本文抛却具体差别,抽象出一个十分简单的存取模型来说明 RAM 的工作原理 。
我们一起聊聊MySQL 索引的底层逻辑

文章插图
图片
从抽象角度看,主存是一系列的存储单元组成的矩阵 , 每个存储单元存储固定大小的数据 。每个存储单元有唯一的地址 , 现代主存的编址规则比较复杂,这里将其简化成一个二维地址:通过一个行地址和一个列地址可以唯一定位到一个存储单元 。上图展示了一个 4 x 4 的主存模型 。主存的存取过程如下:当系统需要读取主存时 , 则将地址信号放到地址总线上传给主存,主存读到地址信号后,解析信号并定位到指定存储单元,然后将此存储单元数据放到数据总线上 , 供其它部件读取 。写主存的过程类似,系统将要写入单元地址和数据分别放在地址总线和数据总线上,主存读取两个总线的内容,做相应的写操作 。这里可以看出,主存存取的时间仅与存取次数呈线性关系,因为不存在机械操作,两次存取的数据的“距离”不会对时间有任何影响 , 例如 , 先取 A0 再取 A1 和先取 A0 再取 D3 的时间消耗是一样的 。
磁盘存取原理上文说过,索引一般以文件形式存储在磁盘上,索引检索需要磁盘 I/O 操作 。与主存不同,磁盘 I/O 存在机械运动耗费 , 因此磁盘 I/O 的时间消耗是巨大的 。下图是磁盘的整体结构示意图 。
我们一起聊聊MySQL 索引的底层逻辑

文章插图
图片
一个磁盘由大小相同且同轴的圆形盘片组成 , 磁盘可以转动(各个磁盘必须同步转动) 。在磁盘的一侧有磁头支架,磁头支架固定了一组磁头,每个磁头负责存取一个磁盘的内容 。磁头不能转动 , 但是可以沿磁盘半径方向运动(实际是斜切向运动) , 每个磁头同一时刻也必须是同轴的,即从正上方向下看,所有磁头任何时候都是重叠的(不过目前已经有多磁头独立技术,可不受此限制) 。下图是磁盘结构的示意图 。
我们一起聊聊MySQL 索引的底层逻辑

文章插图
图片
盘片被划分成一系列同心环 , 圆心是盘片中心,每个同心环叫做一个磁道,所有半径相同的磁道组成一个柱面 。磁道被沿半径线划分成一个个小的段,每个段叫做一个扇区,每个扇区是磁盘的最小存储单元 。为了简单起见 , 我们下面假设磁盘只有一个盘片和一个磁头 。当需要从磁盘读取数据时,系统会将数据逻辑地址传给磁盘,磁盘的控制电路按照寻址逻辑将逻辑地址翻译成物理地址 , 即确定要读的数据在哪个磁道,哪个扇区 。为了读取这个扇区的数据,需要将磁头放到这个扇区上方 , 为了实现这一点,磁头需要移动对准相应磁道,这个过程叫做寻道 , 所耗费时间叫做寻道时间,然后磁盘旋转将目标扇区旋转到磁头下,这个过程耗费的时间叫做旋转时间 。


推荐阅读