首先需要理解磁盘IO的原理
磁盘读取
硬盘中一般会有多个盘片组成,每个盘片包含两个面,每个盘面都对应地有一个读/写磁头。
将磁道划分为若干个弧段,每个磁道上一个弧段被称之为一个扇区(图践绿色部分),扇区是磁盘的最小组成单元。
硬盘通常由重叠的一组盘片构成,每个盘面都被划分为数目相等的磁道,并从外缘的“0”开始编号,具有相同编号的磁道形成一个圆柱,称之为磁盘的柱面。
block:块是虚拟出来的,是操作系统中最小的逻辑存储单位。操作系统与磁盘打交道的最小单位是磁盘块。由于扇区的数量比较小,数目众多在寻址时比较困难,所以操作系统就将相邻的扇区组合在一起,形成一个块,再对块进行整体的操作。
page:操作系统经常与内存和硬盘这两种存储设备进行通信,类似于“块”的概念,都需要一种虚拟的基本单位。所以,与内存操作,是虚拟一个页的概念来作为最小单位,一般一页为4KB(8个扇区,每个扇区125B,8*125B=4KB)。
磁盘读取时间:
- 寻道时间:磁头以径直方向移动到对应磁道。
- 旋转延迟:盘片旋转,将扇区旋转到磁头下。
- 数据传输时间:数据通过数据总线传输到内存的时间。
软件应着重考虑减少寻道时间和延迟时间,其中可以通过尽量将相关信息放在同一盘块,同一磁道中,或者至少放在同一柱面或相邻柱面上,以求在读/写信息时尽量减少磁头来回移动的次数,避免过多的寻道时间。
局部性原理
局部性原理:指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。
三种不同类型的局部性:
- 时间局部性(Temporal Locality):如果一个信息项正在被访问,那么在近期它很可能还会被再次访问。程序循环、堆栈等是产生时间局部性的原因。
- 空间局部性(Spatial Locality):在最近的将来将用到的信息很可能与正在使用的信息在空间地址上是临近的。
- 顺序局部性(Order Locality):在典型程序中,除转移类指令外,大部分指令是顺序进行的。顺序执行和非顺序执行的比例大致是5:1。此外,对大型数组访问也是顺序的。指令的顺序执行、数组的连续存放等是产生顺序局部性的原因。
磁盘预读
为了尽量减少I/O操作,计算机系统一般采取预读的方式,预读的长度一般为页(page)的整倍数。主存和磁盘以页为单位交换数据。当程序要读取的数据不在主存中时,会触发一个缺页异常,此时系统会向磁盘发出读盘信号,磁盘会找到数据的起始位置并向后连续读取一页或几页载入内存中,然后异常返回,程序继续运行。
由于磁盘顺序读取的效率很高(不需要寻道时间,只需很少的旋转时间),因此对于具有局部性的程序来说,预读可以提高I/O效率。
why b、b+
一般查找树
数据在存储中的基本单位为页,这也是进行数据读取时候基本单位,一次读取就是一次IO操作
左边的block在物理上不一定就是相连的,无法发挥局部性原理,这样每次都需要重新寻道,花费时间,随着数据越多,树的高度越高,每次查找的磁盘IO次数多。
B树
B树的每个节点中包含的数据多了,每个节点可以有多个子树,每个节点可以包含多个数据,通过横向扩展数据,减少整棵树的高度。 在数据库的应用中,数据库充分利用磁盘读取原理,将每个节点设为一页(4kb)大小,这样一次IO就可以读取到多个数据,而且在每次进行插入既新建节点时,直接申请一个页的空间,同时计算机分配按页对齐的,再加上局部性原理,可以大大提高效率。
B+树
B+主要是通过将数据全部迁移到叶子节点上,叶子节点只存储数据,非叶子节点只存储指针,这样每个节点就有更多存储空间,从而存储更多的数据。
一般在数据库系统(MySQL)或文件系统中使用的B+Tree结构都在经典B+Tree的基础上进行了优化,增加了顺序访问指针(双向指针),这样在范围查询只需要按照指针遍历即可,提高效率。