持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天 不难发现故事总是从小的开始,再反映应整个社会与时代
从 记录 到 页,再从 页 到 树,都是从小到大,逐渐复杂的过程
每一步变化都是更小的东西构成更大的东西,构成的方式可以多种多样,构成本身也需要信息进行描述
这次来说 B+树 与 页的集合
查找
故事都是从小到大的,这里的也不例外
页中的查找
实际上有两种情况
以主键作为条件
可以利用页目录进行二分查找,快速定位
其他属性为条件
遍历每一条记录
很多页的查找
实际上也就是两个步骤
- 查找到对应的页
- 在对应页中查找记录
但是,我们很难确定记录在哪一页中,只能遍历每一页
页的形成
在上一章过渡时,我们说到,每一个页也是有大小限制的
当页没有满时,直接在该页中插入即可
如果页满了......就需要新建一个页,发生页分裂
- 找到主键小于需插入的记录的最后一条记录
- 移动该页记录,多出来的记录进入到新的一页
- 插入需要插入的记录
索引
每一页都要进行查找,这毫无吸引力
为了加快查找页以及页中的记录搜索,在千呼万唤中,索引出现了
之前我们提到了记录头,这里我们要用到其中的next_record以及recrd_type
页的索引
回想一下,似乎我们说过一句话:下一页记录的主键必然大于当前页的主键
- 页与页之间也通过File Header中的一些字段形成了双向链表
- 与页目录类似,可以采用页最小记录做成页目录项,查找在哪个页时,也可以采用二分的方式
- 归根结底,页目录项实际上也是记录,只不过记录的是每一页开头的最小值信息
-
- 页目录项中只包含索引列以及页号
- 采用存储记录的方式存储页目录项,其中页目录项的record_type字段为1
页与页之间的关系很像记录分组与记录分组之间的关系,页索引实际上可以看作是页目录的加强版
数据即索引,索引及数据
当页目录项很多的时候,和普通记录一样,会增加新的页,所以,问题又变成了,如何找到对应记录页所在页目录项页?
- 那就多建一层,最终会形成一个索引树
也就是传说中的B+树:
- 根节点为第0层
- 每一层都是一个双向链表
- 叶子节点数据集合才是所有的数据
聚簇索引
实际上在InnoDB中可能存在多个索引,毕竟存在这么多不同的列
其中唯一且特殊的索引为聚簇索引
- 使用主键作为建立整个树的索引列
- 叶子节点存储了整一列的完整数据
聚簇索引是InnoDB在建立表的时候,自动创建的(毕竟总要查数据的吧)
二级索引
除了主键,其他的属性列也可以作为索引列,构建起一棵新的B+树
- 使用该属性列作为B+树排序的依据
-
- 为了防止该属性为非唯一属性,一般页目录项为 该属性列值、主键、对应页号,这样能保证记录的顺序
- 叶子节点为只存储 该列值 以及 主键值
获取主键值后,需要再去聚簇索引进行查找
联合索引
除了使用一个列构建索引,也可采用多个列(如a、b)来构建索引
- 在进行排序的时候,这些列之间有优先级顺序
-
- 先按a列排序,a相同时,按照b排序
- 查询时,即使顺序不一样,InnoDB会优化查询语句
- 每个页目录项包含a、b、主键以及页号
-
- 叶子节点包含a、b、主键值
- 同样需要回表
MyISAM
数据与索引分开存储
索引都相当于是二级索引,其子节点为 行号 ,可以看作是主键
最终都需要根据行号去数据区查找真正的数据