文章目录
一、B+树索引
各个数据页组成双向链表,每个数据页中的记录会按照主键值从小到大的顺序组成一个单向链表。
1.1 没有索引时进行查找
假设搜索条件为某个列等于某个常数的情况:
SELECT [查询列表] FROM 表名 WHERE 列名 = xxx;
(1)若此时只有一个页,根据搜索条件不同分为两种情况:
- 以主键为搜索条件:在页目录中使用二分法定位到对应的槽,然后再遍历该槽对应分组中的记录,即可定位指定记录
- 以其他列为搜索条件:数据页中并没有为非主键列建立页目录,所以只能从Infinum记录开始依次遍历
(2)若有很多数据页,此时需要首先沿着双向链表一页一页地根据情况(1)确定此页有没有目标记录,时间复杂度极高。
于是需要一种高效完成搜索的方法——索引。
1.2 索引
先建个表:
其对应的行格式示意图:
关于行格式及相关字段含义参照文章:
https://blog.csdn.net/sunximei/article/details/121249738
1.3 一个简单的索引方案
我们的第一个需求就是快速定位一个记录所在的数据页。想到在一个页中根据主键值定位记录采用的页目录方法,我们也可以为数据页建立一个别的目录。
在建立此目录的过程中需完成两件事:
1. 下一个数据页中的记录主键值需大于上一页中的。
假设每页最多只能存放3条记录。首先向index_demo表插入3条记录:
INSERT INTO index_demo VALUES (1, 4, 'u'), (3, 9, 'd'), (5, 3, 'y');
此时再插入一条记录:
INSERT INTO index_demo VALUES (4, 4, 'a');
由于记录数超过页最大容量,于是分配新页。但为了使得新页中的主键值大于旧页,所以需要将主键值为5的记录移动至新页,然后再将主键值为4的记录插入旧页。这个过程也可称为页分裂。
注:新分配的页编号可能不是连续的,即在磁盘上并不相邻(不过InnoDB设计尽量让其相邻)
2. 给所有的页建立一个目录项
模拟向表中插入多条记录的效果:
由于这些大小为16KB的页在磁盘上并不相邻,所以需要为所有的页编制一个目录,每个页对应一个目录项,每个目录项包括两个部分:
- 页中用户记录的最小主键值key
- 页号page_no
效果如图:
然后将这些目录项在存储器上连续存储(如数组),就可以实现根据主键值快速查找记录(两次二分法)。这个目录就被称为索引。
1.4 InnoDB的索引方案
刚才的简易方案是基于所有目录项都可以在存储器上连续存储的前提下,实际上存在一些问题:
- InnoDB使用页作为管理存储单位的基本单位,即最多保证16KB连续存储空间。所以无法应对过多的目录项
- 执行删除操作时,会导致被删除项后的所有记录都前移,时间复杂度高;若作为冗余留在页