各个数据页可以组成一个双向链表,而每个数据页中的记录会按照主键值从小到大的顺序排列成一个单向链表。每个数据页都会为存储在它里面的记录生成一个页目录,在通过主键值查找某条记录的时候可以在页目录中使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录即可快速找到指定的记录
6.2 索引
要在多个页中根据主键值查找记录时,可以把每个页的最小的那条用户记录和页号存储到一个索引数据页中,这样就可以在这个索引数据页中用二分法快速找到该主键值所在的用户数据页,然后再到数据页中再次二分查找主键值对应的记录
索引数据页和用户数据页结构是一样的,页面类型都是0x45BF
,只是一个保存主键值和页号(目录项记录),一个保存普通用户记录
区别在于:
目录项记录的
record_type
值是1,普通用户记录的record_type
值是0目录项记录只有主键值和页的编号两个列,用户记录的列是自定义的
- 只有目录项记录的
min_rec_flag
属性才可能为1,普通用户记录的min_rec_flag
属性都是0
如果目录项记录太多也需要分页,就需要在再建立一级目录项记录页,形成一棵树
真正的用户记录都存放在B+树最底层的节点上,称为叶子节点。其余用来存放目录项记录的节点称为非叶子节点或内节点,最上边的节点称为根节点
聚簇索引
- 使用记录主键值的大小进行记录和页的排序
- B+树的叶子节点存储的是完整的用户记录
二级索引
- 使用索引列的值大小进行记录和页的排序
- B+树叶子结点存储的并不是完整的用户记录,而只是索引列+主键这两个列的值
- 目录项记录中变成了索引列+页号
通过二级索引查找到主键值后,需要通过主键值到聚簇索引中重新定位完整的用户记录,称为回表
联合索引
可以同时为多个列建立索引,这样会先按第一个列排序,如果第一个列相同,再按第二个列排序
索引注意事项
- 根节点不变
一个B+树索引的根节点自创建便不会再移动(页号不会改变),这样只要我们对某个表建立一个索引,那么它的根节点的页号就会记录到某个地方,后面需要用到这个索引时,都会从那个固定的地方取出根节点的页号,从而访问这个索引
- 内节点中目录项记录的唯一性
因为新插入的记录需要定位到该插入到哪个页中,所以B+树同一层内节点的目录项记录除页号外必须是唯一的
但二级索引的字段值可能不是唯一的,所以二级索引的目录项记录实际上由3部分组成
- 索引列的值
- 主键值
- 页号
这样就相当于对(索引列,主键)建立了联合索引
- 一个页面至少容纳2条记录
MySQL创建和删除索引
创建表的时候可以指定索引
CREATE TABLE 表名 (
各个列的信息 ...,
(KEY|INDEX) 索引名 (需要被索引的一个或多个列)
)
或者在修改表时指定索引
ALTER TABLE 表名 ADD (KEY|INDEX) 索引名 (需要被索引的一个或多个列)
或者删除索引
ALTER TABLE 表名 DROP (KEY|INDEX) 索引名
比如为index_demo
表的c2
和c3
列添加联合索引
CREATE TABLE index_demo (
c1 INT,
c2 INT,
c3 CHAR(1),
PRIMARY KEY(c1),
INDEX index_c2_c3 (c2, c3)
)
删除index_c2_c3
ALTER TABLE index_dmeo DROP INDEX idx_c2_c3