为什么要用建立索引以及为什么要用b+树?
前言:
https://www.youtube.com/watch?v=aZjYr87r1b8 看到了一个印度阿三讲述的B树和B +树。它们在数据库中的作用。精了,以前一直模模糊糊的问题这里一下子就清晰了。这里记录下来。
磁盘结构
抽象出来的磁盘结构:按等份分为n个扇区(Sector),按照n个圆环分为n个轨道(tracks)。如果我要读去某块区域(block)的内容需要用到(轨道号,扇区号)来进行定位。
通常将block块取为512字节。然后block都是从0-511的表示,则我们如果需要读去某段字节,则需要offerset 偏移量的作用,根据block的的初始地址+偏移量即可得到某段字节的位置。
我们需要扇区号、轨道号、偏移量来让我们找出特定块中的特定数据。
数据如何存储在磁盘
尝试了好久电脑画图,无奈还是手画算了。。
首先模拟一张表,这张表的字段都如上图所示,id是10byte,而总共加起来一行记录需要128byte的空间进行存储,假设磁盘中的磁盘块一块存储512byte,则我们可以知道一块磁盘块可以存储4条记录,则存储100条记录则需要25块磁盘块。
想象一下此时我们需要查找一个id为98的记录,那么我们最差最差是不是要遍历这25块磁盘块,即最差打算需要25次io读取操作。
此时,索引的作用就体现出来了。
索引的作用就类似与书本的目录。
如上图所示,我们利用id建立了索引,索引的一条记录是id和一个指向磁盘块指定偏移量位置的指针,即指向一条完整记录。 一条索引记录的大小是id+指针大小,所以远比一整条记录来的要小,这里假设是16byte,则一块磁盘块可以存储32条记录,则此时只需要4块磁盘块即可装下该索引表。这个时候我们再需要一个id为98的记录,只需要遍历4个块,找个索引对应的指针即可找到该记录。
多重索引
假设记录好多,1000,10000条,则索引表也就是1000,10000条数据,这也很大啊,这时候我们只需要向上建立更大的索引,指向索引表的所存储的块中,这也就可以减少io遍历次数。
看到这里,我想大家应该有点眉目了,那么下面用问题来理解一下。
问题
为什么要用建立索引?
未建立索引的时候,如果查找的时候需要将存储数据的硬盘块一个个读取,找出存储在其中的记录的id进行比较,这样的话效率低。
建立索引之后,可以利用一条索引记录的大小比一条行记录的小,让一个硬盘块可以存储更多索引记录,然后查询的时候,只需要访问少量的硬盘块。
索引可以减少读取硬盘块的次数。提高查询的速度。
为什么要用b+树,而不是红黑树、b树?
使用b+树来实现索引,由于数据主要是存储在硬盘中,所以查询的主要耗费的时间在硬盘的读取上,所以衡量使用哪种数据结构更优,就是要看谁访问硬盘的次数少。
磁盘预读原理:磁盘往往不是严格按需读取,而是每次都会预读,即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据【这个一定的长度就是一个节点的大小设置为16K】放入内存。
我们知道磁盘预读原理,而b+树的节点可以有多个key,使用b+树可以将同一节点内的key存储在同一块中,这也可以只需一次i/o操作即可读取出一个结点的所有key。并且b+树的节点可以有多个key意味着树的高度就会变矮,意味着查询的时候访问硬盘的次数也就会随着减少。
反观红黑树,一个结点只能存放一个key,则每一个结点都需要进行一次i/o操作且针对的是一个key,并且树的高度也比较高,意味着查询的时候需要遍历多个结点,i/o次数多
那为啥不是b树呀=。=?
B+Tree区别B-Tree(B树)的地方在于,B+Tree的非叶子结点只存储导航信息,数据全部存储在叶子结点处并且用链表连接
B+Tree的非叶子结点只存储导航信息,意味着他可以存放更加多的key,进一步缩减了树的高度,减少i/o次数,
而且叶子节点之间都是链表的结构,所以B+ Tree也是可以支持范围查询的,而B树每个节点 key 和 data 在一起,则无法区间查找
末尾:
这是看着大叔视频手写下的一下心得,不够严谨,如果有错希望大家指出