image-20210616154139828
B+
树from
join
on
where
group by(开始使用select的别名,后面的语句都可以使用)
avg,sum...(各种函数)
having
select
distinct
order by
limit
所有的查询都是从
from
开始的,在执行过程中,每个步骤都会为下一个步骤生成一个虚拟表vt1
(选择相对较小的表做基础表)
索引是一种数据结果,用来提高获取数据的效率。
聚簇索引的排列顺序和记录的排列顺序是一致的,所以查询比较快,只要找到一个索引值记录,其余连续性的记录在物理表也会连续存放
缺点是:新增比较慢,为了保证索引的排列顺序和记录的排列顺序是一致的,在插入数据的时候,会对数据进行重新排序。
> alter table `rumenz` add primary key(`id`);
> alter table `rumenz` add unique(`name`);
> alter table `rumenz` add index index_name(`name`);
> alter table `rumenz` add fulltext(`content`);
> alter table `rumenz` add index_name(`name`,`age`);
采用哈希算法,和hashmap类似,之需要一次哈希算法就可以马上定位,速度非常快,本质就是把索引列换算成哈希值,根据这个哈希值进行定位查找。
哈希索引的缺点
MySQL为什么要使用B+树索引?
表->段->区->页->行
在数据库中,不论读哪一行数据,还是读多行数据,都是将这些行所在的页进行加载。也就是存储空间的基本单位就是页。
一个页就是一颗B+树的节点,数据库I/O操作的最小单位是页,与数据库相关的内容都会存储在页的结构里。
img
img
页的最主要目录是存储记录,页中的记录是以单链表形式存储的。单链表的有点是插入,删除方便,缺点是检索效率不高,最坏的情况要遍历所有节点。因此页目录中提供了二分查找,来提高检索的效率
img
我们为 user 表(用户信息表)建立了一个二叉查找树的索引。
图中的圆为二叉查找树的节点,节点中存储了键(key)和数据(data)。键对应 user 表中的 id,数据对应 user 表中的行数据。
二叉树的特点是:任何节点的左子节点的键值都小于当前节点的键,右子节点的键值都大于当前节点的键值。顶端的节点被称为根节点,没有子节点的节点我们称为叶子节点。
查找 id=12 的用户信息,利用我们创建的二叉查找树索引,查找流程如下
利用二叉树可以快速找到数据,但是,如果上面的二叉树是上面的结构,则二叉树就会变成一个链表。如果我们需要查找id=17的用户信息,我们需要需要查找7次,相当于全表扫描了,效率很低。——于是我们就有了平衡二叉树。
2
平衡二叉树又称AVL树,在满足二叉树特性的基础上,要求每个节点的左右子树的高度差不能超过1。
3
当不平衡时,则需要调整二叉树的平衡。
红黑树与AVL相比,红黑树并不追求严格的平衡,而是大致的平衡,只是确保从根到叶子的最长路径不多于最短的可能路径的两倍长。红黑树最大的特点是每个节点都属于两种颜色(红色或黑色)之一,且节点颜色的划分需要满足下面的规则。
下面是一颗标准的红黑树
img
红黑树与AVL树相比,红黑树的查询效率会有所下降,这是因为树的平衡性变差,高度更高。
但红黑树的删除效率大大提高了,因为红黑树同时引入了颜色,当插入或删除数据时,只需要进行O(1)次数的旋转以及变色就能保证基本的平衡,不需要像AVL树进行O(lgn)次数的旋转。总的来说,红黑树的统计性能高于AVL。
因此在实际中AVL树使用相对比较少,而红黑树使用非常广泛。如Java中的TreeMap使用红黑树存储排序键值对。Java8中的HashMap使用链表+红黑树解决哈希冲突问题(当冲突比较少的时候,使用链表,当冲突多的时候采用红黑树)
在数据再内存中的情况(如上述的TreeMap和HashMap),红黑树的表现是非常好的。但是对于数据在磁盘等辅助存储的设备情况中(如:Mysql数据库),红黑树并不适用,因为红黑树相对很高。当数据在磁盘中时,磁盘IO会成为性能瓶颈,设计的目标应该是降低IO次数,而树的高度越高,增删改查所需要的IO次数也会越多,会严重影响性能。
内存的大小有限,并且容易丢失,所以像数据库这种应用会把数据和索引存放到磁盘这种外围设备中。但是磁盘的读取速度相比与内存会差百,千倍,所以我们应该尽量减少查磁盘的次数。
从磁盘中读取数据时,都是按磁盘块来读取的,并不是一条一条读的,如果我们尽可能多的把数据放进磁盘块中,那么一次磁盘读取就会读取更多的数据,那么查询数据的时间也就会降低。如果我们使用树这种数据结构作为索引的数据结构,那我们每查找一次数据就要从次磁盘中读取一个节点,也就是我们说的磁盘块。平衡二叉树可是每个节点只存储一个键值和数据的。那说明什么?说明每个磁盘块仅仅存储一个键值和数据!那如果我们要存储海量的数据呢?可以想象到二叉树的节点将会非常多,高度也会极其高,我们查找数据时也会进行很多次磁盘 IO,我们查找数据的效率将会极低!
数据库要存海量数据,AVL树每个节点只会存储一个键值和数据,并且数据是存储在磁盘上的,当我们存储一个数据时,速度会很慢,应该减少从磁盘读取数据的次数。当我们使用AVL树,树的高度会很高,会进行多次磁盘IO,效率会很低。
因为要存储的数据是海量的,AVL每个节点只能存储一个键值和数据,并且数据存储在磁盘上,当我们存储一个数据,速度会很慢,我们应该减少读取磁盘的次数,使用AVL树,树的高度会很高,会进行很多次磁盘IO,查找数据的效率会非常的低。
img
为了解决AVL树这个弊端,我们需要找到一个单节点能存储多个键值和数据的平衡树,也就是下面要说的B树
img
图中的p节点为指向子节点的指针,二叉查找树和平衡二叉树也有。
图中的每个节点称为页,页就是我们上面说的磁盘块,在MySQL中数据读取的基本单位是页,所以我们这里叫做页更符合MySQL中索引的底层数据结构。
B树相对于平衡二叉树,每个节点存储了更多的键值(key)和数据(data),并且每个节点有更多的子节点,最多子节点的个数一般称为阶。
image-20210621115010194
基于这个特性,B 树查找数据读取磁盘的次数将会很少,数据的查找效率也会比平衡二叉树高很多。
应用:B树在数据库中有一些应用,如mongodb的索引使用了B树结构。但是在很多数据库应用中,使用了是B树的变种B+树。
img
数据库中页的大小是固定的,InnoDB中页的默认大小是16KB,如果不存储数据,就会存储更多的键值,相应的树的阶数(节点的子节点数)就会越大,所构建成的树就会又矮又胖,这样每次查数据的磁盘IO就会更少,数据查询效率更快。
使用B+树进行范围查找,顺序查找,分组查找,去重相当容易,因为B+树的数据是按顺序存放的。而B树的数据分散在每个节点,要实现这一点很困难。B+树各个页之间之通过双向链表来连接的,叶子节点的数据是用单向链表进行连接的。在 InnoDB 中,我们通过数据页之间通过双向链表连接以及叶子节点中数据之间通过单向链表连接的方式可以找到表中所有的数据。MyISAM 中的B+树和InnoDB中的实现有一点区别,MyISAM中的B+树的叶子节点存放的是数据文件的地址。
B树在提高了IO性能的同时并没有解决数据遍历效率低下的问题,B+树只需要遍历叶子节点就能遍历真个树,数据的范围查找非常普遍,而B树就不支持这样的操作。
在Mysql中B+树索引按照存储方式的不同分为聚集索引和非聚集索引。
相关命令
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有