说明:mysql底层使用的时B+树,mysql索引是放在磁盘上面的,因此每次读取索引时通过IO从磁盘读取。
1、hash索引:无规则、不能排序
2、二叉树:解决hash索引不能排序问题,但是当数据有序时会出现线性排列,树的深度会变得很深,会消耗大量IO。
3、平衡二叉树:解决二叉树数据有序时出现的线性插入树太深问题,树的深度会明显降低,极大提高性能,但是当数据量很大时,一般mysql中一张表达到3-5百万条数据是很普遍的,因此平衡二叉树的深度还是非常大,mysql读取时还是会消耗大量IO,不仅如此,计算从磁盘读取数据时以页(4KB)为单位的,及每次读取4096byte。平衡二叉树每个节点只保存了一个关键字(如int即4byte),浪费了4092byte,极大的浪费了读取空间。
4、B-树:解决平衡二叉树树深度的问题,解决了平衡二叉树读取消耗大量内存空间的问题。因为B-树每个节点可以存放多个关键字,最大限度的利用了从磁盘读取的内存空间,单节点存放多个关键字同时也大大减少了树的深度。极大的提高了mysql的查询性能。但是B-树还是有缺点,B-树对有范围查找的查询(如age>20)时采用的还是中序排序法,因此也需要多遍历,并且查询性能不稳定,比如查询(select * from table where id = 222 和 select * from table where id = 223)时在查询效率(耗时)上可能会存在一定的差别,因为B-树还是将关键字,这里为id,存放在根节点和叶节点的,如果运气好,可能id=222这个关键字就在第一个节点,消耗一次IO就找到了,而id=223可能在叶节点,需要消耗3次IO才能找到。因此B-树对同一条sql语句的查询性能可能会有很大影响(确实感觉有点扯,但是事实时这样)。
5、B+树:将关键字全部存放在叶子节点(查询更稳定,同一条mysql语句执行效率时相同的,都会消耗3次IO),将相邻叶子节点的地址保存起来(相比于B-树,对于mysql的范围查找不用再使用中序查找,而是可以直接快读获取到。)
总结:mysql最终使用B+树为mysql索引的底层实现,mysql维护索引有很大的消耗的,会极大的影响数据库的增、改、删操作,因此建立有用的索引很重要,索引字段所占字节越少,mysql一次读取的关键字也会也多,消耗IO会更少、命中率会更大,查询效率随之也会更高。
B+树是B-树的变种(PLUS版)多路绝对平衡查找数,他拥有B-树的优势。
B+树扫库、表能力更强(因为B+树只在叶子节点保存数据了,因此每次IO读取的数据会更多。)
B+树的磁盘读写能力更强(因为B+树只在叶子节点保存数据了,因此每次IO读取的数据会更多。)
B+树的排序能力更强。(因为叶子节点添加了左边最大的指向右边最小的,有天然的排序。)
B+树的查询效率更加稳定。(B-树可能一次IO就命中查询,但是同一类查询,不同的值可能一次IO就命中、可能3次IO才命中,查询效率不稳定。而B+树IO消耗次数是固定的,因此叶子节点才保存数据地址,更加稳定。)
下面是我对平衡二叉树的插入实现代码(效率不高,不过最终花了大概一周时间还是实现了),这也说明了mysql维护索引所带来的消耗,B+树实现起来会更难,更复杂,因此维护成本会更高。:
插入实现关键点:
1.插入新节点时 节点左
2.计算每个节点的高度以及平衡因子
3.知道使树不平衡的4种类型以及旋转方式(RR、LL、RL、LR)
package com.kf.tree;
import org.apache.commons.lang3.StringUtils;
public class AVL {
private Node root = null;//根节点
private Node newNode = null;//最新节点
private boolean isBanlance = true;
private int count &#