多路平衡树之B树
B-树
- B树中允许
一个结点中包含多个key
- 实际应用中B树的阶数一般都比较大(通常大于100),即使存储大量的数据,B树的高度仍然较小
B树的特性
- M阶B树每个结点最多包含
M-1
个key
- 每个结点最多能有M个子结点
- 根结点至少有两个子结点
- M阶 B树的度为M(度 为结点拥有的子树数(链数),树的度为树内各结点的度的最大值)
- 一个M阶B树,若有N个结点(一个结点最多有M-1个key),则树的高度最大为h=logM(N+1 / 2)
- 注:可类比有N个结点的二叉树的最大高度为|log2N|+1,以2为底N的对数结果+1
B+树
-
与B树的差异
- 非叶结点仅具有索引作用,即非叶子结点只存储key,不存储value
- 树的所有叶结点构成一个有序链表,可以按照key排序的次序遍利全部数据
-
B+ 树的优点
- 由于B+树在
非叶子结点
上不包含真正数据,只当作索引使用
,因此在内存相同
的情况下,能够存放更多的key
- B+树的
叶子结点都是相连
的,因此对整棵树的遍历只需要一次线性遍历叶子结点
即可。而且由于数据顺序排列并且相连
,所以便于区块查找和搜索
。而B树则需要进行每一层的递归遍历
,例如,查找索引10~80之间的数据
,mysql内部会在B树上查找key为10所在的叶子节点(在叶子节点上,每个区块存储的键值对数量为B+树的阶数),找到后向后遍历索引直至到80,由于B+树每个叶子节点内部最后一个key的next都指向相邻的叶子节点,所以可以直接遍历到80处,取得每个索引对应的数据(value),B+树这样的结构改进了链表中查找数据为O(N)的时间复杂度,范围查找的时间复杂度降为O(N+k),k即为查找区间。
- 由于B+树在
-
B树的优点
- 由于B树的每一个结点
都包含key和value
,当查找key和value时,只需要找到key所在的位置,就能找到value,但B+树只有叶子结点存储数据
,所以索引每一次查找,都必须一次一次向下,一直找到树的最大深处
,时间复杂度为logN
logN
- 由于B树的每一个结点
B+树在MySQL数据中的应用
- 分支节点在
内存中以平衡树形式
存储索引(key),实际上内存是有限的,索引是一文件形式存取到磁盘上,查找时将索引文件加载进内存,再在内存中根据索引所在区间去指定磁盘位置(磁道)查找数据;叶子节点在磁盘上以链表结构
存储的数据(key-value键值对),磁盘读取数据是预度的方式
MyISAM引擎
-
MyISAM的索引文件仅仅保存数据记录的地址,地址是由主键运算过来的
-
非聚集索引,key是主键,value即索引的data域存储的是
数据文件记录的地址
-
在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,也是存储的记录地址,只是主索引要求key是唯一的,而辅助索引的key可以重复。
InnoDB引擎
-
InnoDB的数据文件本身就是索引文件,所以
表必须有主键
(如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。)- InnoDB表数据文件本身就是主索引
- InnoDB的辅助索引data域存储相应记录主键的值
-
聚集索引,主键聚集,
key是表中的主键
,value即data域保存完整的数据记录
,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。 -
辅助索引存储的是相应记录的
主键的值
,即辅助索引引用主键的值为data域 -
注意事项
:
- 不要使用过长的字段作为主键,辅助索引的data域存的是主键,过长的主键会使辅助索引变得很大
- 尽量使用单调的字段作为主键,非单调主键在插入数据时,为了维持B+tree结构会进行左右旋转或分裂调整等操作,浪费性能
索引优化
- 联合索引(为多个字段建立一个索引),最左前缀原则(查询条件为联合索引顺序)
- 对 where,on,group by,order by 中出现的列使用索引
- 为较长的字符串使用前缀索引(order by与group by 无效)
- 区分度高的列作为索引
- 对于like 模糊查询,不要把%放在前面
- 正则表达式不能使用索引
- 索引会提高查询效率,但索引过多会影响插入,删除操作效率
- 不建议使用过长的字段作为主键,因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大
- 用非单调的字段作为主键在InnoDB中不是个好主意,因为InnoDB数据文件本身是一颗B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。
查询优化
- 避免使用
select *
或者查询加上limit
,MySQL客户端与服务端通信协议是半双工
,同一时间只能单向通信(客户端→服务端
或服务端→客户端
) 查询缓存,hashMap
写,缓存失效、系统僵死
读,SQL缓存检查,性能消耗
B树存储数据
B树在磁盘文件中的应用
磁盘IO
- 对磁盘的访问时间分为
寻道时间
旋转时间
传送时间
- 预读。每一次主存对磁盘的IO存取操作很费时,磁盘每次都会预读
- 页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页,
预读的长度一般为页的整数倍
,主存和磁盘以页为单位交换数据 - 文件系统的利用了磁盘预读原理,将一个结点大小设为等于一个页(1024个字节或其整数倍),这样每个结点只需要一次I/O就可以完全载入。那么3层的B树可以容纳102410241024差不多10亿个数据,如果是普通BST树,则需要30层,需要大量I/O操作,
而B树在10亿个数据中查找目标值,只需要小于3次硬盘读取就可以找到目标值
大大提高IO的操作效率
严律己、宽待人