第6章 快速查询的秘籍——B+树索引
InnoDB数据页的7个组成部分,各个数据页可以组成一个双向链表,每个数据页中的记录会按照主键值从小到大的顺序组成一个单向链表,每个数据页都会为存储在内的记录生成一个页目录,通过主键查找某条记录时可以在页目录中使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录即可快速找到指定记录。
其中页a、页b、页c...页n这些页可以不再物理结构上相连,只要通过双向链表相关联即可。
6.1 没有索引时进行查找
6.1.1 在一个页中查找
-
以主键为搜索条件 在页目录中使用二分法快速定位到对应的槽,再遍历该槽对应分组中的记录即可快速找到指定的记录
-
以其他列作为搜索条件 因为在数据页中并没有对非主键列建立所谓的页目录,所以无法通过二分法快速定位相应的槽。这种情况下只能从最小记录开始依次遍历单链表中的每条记录,然后对比每条记录是不是符合搜索条件
6.1.2 在很多页中查找
- 定位到记录所在的页
- 从所在的页内查找相应的记录
6.2 索引
CREATE TABLE index_demo(
c1 INT,
c2 INT,
c3 CHAR(1),
PRIMARY KEY (c1)
) ROW_FORMAT=Compact;
行格式示意图:
其它信息:包括其他隐藏列的值以及记录的额外信息
方便理解,去掉其他信息示意图:
记录放到页里的示意图:
6.2.1 一个简单的索引方案
因为各个页中的记录并没有规律,我们并不知道搜索条件匹配哪些页中的记录,所以不得不依次遍历所有的数据页。建立一个能快速定位记录所在页的目录,需要完成:
下一个数据页中用户记录的主键值必须大于上一页中用户记录的主键值
INSERT INTO index_demoVALUES(1, 4, 'u'),(3, 9, 'd'),(5, 3, 'y');
INSERT INTO index_demoVALUES(4, 4, 'a');
新分配的数据页编号可能并不是连续的,使用的这些页在存储空间可能并不挨着,他们只是通过维护着上一页和下一页的编号而建立链表关系。另外,页10中用户记录最大的主键值是5,而28页中有一条记录的主键值是4,不符合下一个数据页中用户记录的主键值必须大于上一页中用户记录的主键值的要求,所以插入主键值为4的记录的时候伴随一次记录移动。
这个过程称为页分裂
给所有页建立一个目录项 由于数据页的编号并不是连续的,所以向index_demo表插入许多记录后,这些16KB的页在物理存储上可能并不挨着,所以想要在这么多页中根据主键值快速定位某些记录所在页,每个页对应一个目录项
目录项包括
- 数据页中的记录的最小主键值,用key来表示;
- 页号,用page_no表示。
以页28为例,它对应目录项2,这个目录项包含着该页的页号28以及该页中用户记录的最小主键值5.只需把几个目录项在物理存储器上连续存储,就可以实现根据逐渐快速查找某条记录的功能。比如查找主键值为20的记录:
先从目录相中根据二分法快速确定出主键值为20的记录在目录项3中,它对应的页是页9
再根据在页中查找记录的方式去页9中定位具体的记录
这个目录有个别名叫索引