1、索引的本质
索引(Index)是帮助MySQL高效获取数据的数据结构。
2、InnoDB支持常见的索引
B+树索引、
全文索引、
哈希索引,
其中比较关键的是B+树索引
3、HashMap不适合做数据库索引?
1.hash表只能匹配是否相等,不能实现范围查找
2.当需要按照索引进行order by时,hash值没办法支持排序
3.组合索引可以支持部分索引查询,如(a,b,c)的组合索引,查询中只用到了a和b也可以查询的,如果使用hash表,组合索引会将几个字段合并hash,没办法支持部分索引
4.当数据量很大时,hash冲突的概率也会非常大.
4、B+Tree
1.B+树索引就是传统意义上的索引,这是目前关系型数据库系统中查找最常用和最为有效的索引
2.B+树索引的构造类似于二叉树,根据键值(Key Value)快速找到数据。
//注意B+树中的B不是代表二叉(binary),而是代表平衡(balance),因为B+树是从最早的平衡二叉树演化而来,但是B+树不是一个二叉树。
在二叉树之前,先了解一下二分查找:
二分查找法(binary search) 也称为折半查找法,用来查找一组有序的记录数组中的某一记录。
找到数字48对应的下标:
1.通过3次二分查找 就找到了我们所要的数字,而顺序查找需8次
2.所以为了索引查找的高效性,我们引入了二叉查找树
5、二叉树
(1)树(Tree):N个结点构成的有限集合
1.树中有一个称为”根(Root)”的特殊结点
2.其余结点可分为M个互不相交的树,称为原来结点的”子树”
树与非树
树的一些基本术语
二叉查找树首先肯定是个二叉树,除此之外还符合以下几点:
1.左子树的所有的值小于根节点的值
2.右子树的所有的值大于或等于根节点的值
3.左、右子树满足以上两点
但是二叉查找树,如果设计不良,完全可以变成一颗极不平衡的二叉查找树
因此若想最大性能地构造一棵二叉查找树,需要这棵二叉查找树是平衡的,从而引出了新的定义——平衡二叉树,或称为AVL树。
平衡二叉树(AVL-树)
1.它是一棵二叉排序树,它的左右两个子树的高度差(平衡因子)的绝对值不超过1
2.并且左右两个子树都是一棵平衡二叉树
//目的:使得树的高度最低,因为树查找的效率决定于树的高度
1.平衡二叉树的查找性能是比较高的,但是维护一棵平衡二叉树的代价是非常大的
2.通常来说,需要1次或多次左旋和右旋来得到插入、更新和删除后树的平衡性。
B+树
B+ 树是从平衡二叉查找树演化而来(但B+树不是二叉树,而是一个多叉查找平衡树)
将其改造成 B+ 树
树的阶数表示一个节点最多能有多少个子节点
每个叶子页(LeafPage)存储了实际的数据
如下图中有的叶子页就存放了3条数据记录,当然可以更多,叶子节点由小到大(有序)串联在一起,叶子页中的数据也是排好序的;
归纳出B+树的几个特征:
1.相同节点数量的情况下,B+树高度远低于平衡二叉树
2.非叶子节点只保存索引信息和下一层节点的指针信息,不保存实际数据记录
3.每个叶子页(LeafPage)存储了实际的数据,比如上图中每个叶子页就存放了3条数据记录,当然可以更多,叶子节点由小到大(有序)串联在一起,叶子页中的数据也是排好序的;
4.相邻的叶子节点之间用指针相连
5.树的层级越低,查询的效率越高
//注意:叶子节点中的数据在物理存储上完全可以是无序的,仅仅是在逻辑上有序(通过指针串在一起)
为什么MySQL不用B树而使用B+树呢?
1.因为B数据每个节点都存储数据,每次查询的数据大小固定,就会造成每次查询返回的数据的条数变少,相同数据规模的情况下B树会增加io次数,而B+树,则数据量较小,一次可以返回多条记录,io次数较少
2.范围查询B+树明显优于B树
为什么关系型数据库都选择了B+树,这个和磁盘的特性有着非常大的关系。
为了提高效率,要尽量减少磁盘I/O。为了达到这个目的,磁盘往往不是严格按需读取,而是每次都会预读,即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存,这个称之为预读。
预读的长度一般为页(page)的整倍数。页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页,页大小通常为4k。
按照磁盘的这种性质,如果是一个页存放一个B+树的节点,自然是可以存放很多的数据的,比如InnoDB里,默认定义的B+树的节点大小是16KB,这就是说,假如一个Key是8个字节,那么一个节点可以存放大约1000个Key,意味着B+树可以有1000个分叉。同时InnoDB每一次磁盘I/O,读取的都是 16KB的整数倍的数据。也就是说InnoDB在节点的读写上是可以充分利用磁盘顺序IO的高速读写特性。
同时按照B+树逻辑结构来说,在叶子节点一层,所有记录的主键按照从小到大的顺序排列,并且形成了一个双向链表。同一层的非叶子节点也互相串联,形成了一个双向链表。那么在实际读写的时候,很大的概率相邻的节点会放在相邻的页上,又可以充分利用磁盘顺序IO的高速读写特性。
所以我们对MySQL优化的一大方向就是 尽可能的多让数据顺序读写,少让数据随机读写 。
磁盘顺序读取的效率很高(不需要寻道时间,只需很少的旋转时间),一般来说,磁盘的顺序读的效率是随机读的40到400倍都有可能,顺序写是随机写的10到100倍。