1. 基本搜索结构
对比于二叉搜索树、AVL树和红黑树,一般用于数据内存查找。他们不适合用于数据量很大的情况,因为一次性无法加载到内存中。
上面方法其实只在内存中保存了每一项数据信息中需要查找的字段以及数据在磁盘中的位置,整体的数据实际也在磁盘中(但是读取磁盘的速度相较于内存来说,那真的是慢的不行)。
缺陷:
- 树的高度比较高,查找时最差情况下要比较树的高度次
- 数据量如果特别大时,树中的节点可能无法一次性加载到内存中,需要多次IO
那如何加速对数据的访问呢?
- 提高IO的速度
- 降低树的高度—多叉树平衡树
2. B树概念
B树是一颗M路的平衡多叉搜索树。
性质:
- 根节点至少有两个孩子
- 每个非根节点至少有M/2(上取整)个孩子,至多有M个孩子
- 每个非根节点至少有M/2-1(上取整)个关键字,至多有M-1个关键字,并且以升序排列
- key[i]和key[i+1]之间的孩子节点的值介于key[i]、key[i+1]之间
- 所有的叶子节点都在同一层
2.1 B树的插入分析
为了简单起见,假设M = 3. 即三叉树,每个结点中的孩子数量为M=3个,关键字数量为M-1=2个,孩子永远比关键字多一个。
插入过程总结:
- 如果树为空,直接插入新节点中,该节点为树的根节点
- 树非空,找待插入元素在树中的插入位置(注意:找到的插入节点位置一定在叶子节点中)
- 检测是否找到插入位置(假设树中的key唯一,即该元素已经存在时则不插入)
- 按照插入排序的思想将该元素插入到找到的节点中
- 检测该节点是否满足B树的性质:即该节点中的元素个数是否等于M,如果小于则满足
- 如果插入后节点不满足B树的性质,需要对该节点进行分裂:
①申请新节点
②找到该节点的中间位置
③将该节点中间位置右侧的元素以及其孩子搬移到新节点中
④将中间位置元素以及新节点往该节点的双亲节点中插入,即继续4 - 如果向上已经分裂到根节点的位置,插入结束
总结:
- 根结点的关键字数量为[1,M-1],孩子的数量[2,M],非根结点的关键字数量为[M/2-1,M-1],孩子的数量[M/2,M]
- B树是从非根结点开始,然后往上分裂(是一个倒着的过程)。
- 分裂既保证了结点的空间利用率,又保证了平衡
- 时间复杂度可以认为是logN(以M为底)
3. B+树和B*树
B+树相比于B树又是更加明显,因为B树的规则有点绕并且复杂,其次B树不方便遍历(要么使用层序遍历,要么使用递归遍历)
B+树相比于B树的变化:
- 一个结点中的关键字数量和孩子的数量相等
- 所有值都要出现在叶子节点上,非叶子结点中的值只是充当路径索引,并且要把所有叶子结点都链接起来,为了方便遍历(非叶子结点由叶子结点的最小值构成)
B*树相比于B+树变化:
- 非叶子结点也链接起来了
- 两个结点满了以后再分裂,保证每个结点中key的数量
4. MyISAM
MyISAM引擎是MySQL5.5.8版本之前默认的存储引擎,不支持事务,支持全文检索,使用B+Tree作为索引结构,叶节点的data域存放的是数据记录的地址,其结构如下:
上图是以以Col1为主键,MyISAM的示意图,可以看出MyISAM的索引文件仅仅保存数据记录的地址。在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复。如果想在Col2上建立一个辅助索引,则此索引的结构如下图所示:
同样也是一棵B+Tree,data域保存数据记录的地址。因此,MyISAM中索引检索的算法为首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其data域的值,然后以data域的值为地址,读取相应数据记录。 MyISAM的索引方式也叫做“非聚集索引”
总结:
- 每一张表都对应一颗B+树
- 表中主键就是B+树的key,所以一般都要求数据主键是不能冗余的。
- 第一种情况:(主键查找)直接利用B+树的特性进行查找,非常快
select * from t_score where id = 30; - 第二种情况:(非主键查找)那就需要进行全表扫描
select * from t_score where name = ‘Tom’; - 但是如果想要这种非主键查找变快一些怎么办呢?那就重新以这个值为key建立一个辅助索引,表要找完,不能找到一个就停止,因为辅助索引是允许数据冗余的。所以limit 1可以提高查找的效率,是因为找到一个就可以停止了,不用在继续查找。
- 主索引和辅助索引他们都是指向同一份存储的数据。
- 非聚集索引:辅助索引索引中存储的应该是对应主键的key值的地址(所以上图是由问题的),所以先通过辅助索引中的地址找到主键key值,然后在通过主键中存储的地址找到数据在磁盘中存储的位置。这个就叫做非聚集索引
5. InnoDB
InnoDB存储引擎支持事务,其设计目标主要面向在线事务处理的应用,从MySQL数据库5.5.8版本开始,InnoDB存储引擎是默认的存储引擎。InnoDB支持B+树索引、全文索引、哈希索引。但InnoDB使用B+Tree作为索引结构时,具体实现方式却与MyISAM截然不同
。
第一个区别是InnoDB的数据文件本身就是索引文件。MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而InnoDB索引,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。
上图是InnoDB主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录,这种索引叫做聚集索引(简单说:不需要在通过辅助索引先找到主键的key值,然后在找到存储在磁盘中的具体位置,而是直接存放的一个地址就是数据存放在磁盘中的位置)。因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有),如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。
第二个区别是InnoDB的辅助索引data域存储相应记录主键的值而不是地址,所有辅助索引都引用主键作为data域。
聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索 引获得主键,然后用主键到主索引中检索获得记录。
简单理解事务:
一张表存储的大家微信钱包的月
A转账100元给B
update Amoney = Amoney-100 from xxx where name = A;
update Bmoney = Bmoney+100 from xxx where name = B;
假设第一条执行成功,第二条执行失败,那么这里就会出现大问题。所以要么都成功,要么都失败,事务就可以解决这个事情
执行两条sql语句之前开启事务
执行两条sql成功,则提交事务
执行失败,则回滚事务(这里可以去结合数据库的索引事务在进一步了解)