快速查询的秘籍 —— B+索引的建立

前言

之前的文章说过,InnoDB存储数据的单位是页,各个数据页之间采用双向链表连接起来;而每个数据页中的记录之间又通过单向链表连接,而记录又分为若干个,组采用最大记录的记录信息作为信息,多个槽组合成页目录;当用户查询某条记录 A 时,先使用二分法在页目录中找到主键值比 A 的主键值大且差值最小的,然后再使用二分法找到对应的记录。

没有索引的查找

在一个页中查找

在一个页中查找一条记录,当知道主键时可以采用前言中的方法快速查找到对应的记录;
但是如果是其他列信息为查询条件就没这么幸运了,因为页中的记录都是根据主键排序的,无法通过二分法查找到记录,只能一条条遍历。

在很多页中查找

在没有索引的情况下只能通过双向链表遍历页中数据才能够找到对应的记录。
注意:是通过双向链表遍历页,进入到页中使用二分法查找页目录来确定此页中是否存储在对应记录,并不是遍历所有记录。

索引

在真实业务中,数据记录往往是非常多的,一页无法将记录存储完毕,需要很多页来存储。而通过双向链表遍历的方法查找记录是相当低效的,严重的还可能导致数据库崩溃。所以开发数据库的叔叔们给出了索引的概念。

页分裂

当用户插入用户记录的时候,会进行一系列的判断。首先判断本页的记录存储空间是否已满,如果满了就会进行重新排布,同时生成一个新的页空间,将主键靠后的记录分派到新页中,我们称这个过程为页分裂。学习过数据结构中 B+ 树的同学可能会感觉到熟悉。
页分裂具体流程如下图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JuxDbge8-1643190422249)(https://kuangstudy.oss-cn-beijing.aliyuncs.com/bbs/2022/01/26/kuangstudy1bb8b927-da46-4120-be3e-c9dddd04f2ad.png “页分裂后”)]

索引的诞生

当记录数越来越多,数据页也越来越多的时候,数据库的运行效率就会变得极低,为了提高查询的效率。InnoDB采用了和存储记录时一样的方法,给数据页创造一个目录,使用这些目录记录就能通过二分法快速定位到记录在那个数据页中。

那么什么是索引的呢?

索引说白了就是数据页的目录,其本质上也是记录,只不过其存储的是页号 + 列 的信息,页号就是存储真实数据的页,主要是为了做出区分。
为了区分页目录,下面将数据页的目录称之为目录项记录,而将存储真实数据的记录称之为用户记录

目录项记录主要包含两个方面的字段:

  • 页中用户记录的最小的主键值
  • 页号

具体如下图:

怎么区分记录

既然都是记录,那么这么进行区分呢?其实可以通过记录头信息中的record_type属性来区分,具体的属性为:

  • 0:普通的用户记录
  • 1:目录项记录
  • 2:最小记录
  • 3:最大记录

索引的完善

学习过数据库的都知道索引的底层逻辑是 B+ 树,但是目前出现的并不是一颗树,这是怎么回事呢?
其实是索引并没有完善,还是会有隐患。当页数越来越多,尽管通过目录项记录可以快速定位到数据页,但是当目录项记录逐渐增多,遍历查找目录项记录的效率降低了,整体效率也高不上去,所以开发数据库的叔叔们将这些记录使用页来存储,通过处理用户记录的方式来处理目录项记录
目录项记录用数据页存储,当目录项记录的数据页足够多的时候,可以为这些数据页再创建目录项记录,如此反复,这样的操作最后都会结束,然后终止于根节点。

索引的分类

索引根据排序的列不同分为三种索引:聚簇索引、二级索引、联合索引

聚簇索引

聚簇索引是InnoDB的默认索引,也是InnoDB引擎的数据库在存储数据时使用的索引。是的,索引并不是程序员创建才有,当插入数据时,InnoDB引擎数据库就将数据按照聚簇索引的方式进行了排列,以方便后续查询。

那么聚簇索引是什么呢?

聚簇索引就是根据主键+页号为关键字排序的索引,聚簇索引有两个特点:

  1. 聚簇索引是根据主键值大小进行记录和页的排序,这包含三个方面的意思:
    - 页内记录根据主键值大小排序并使用单向链表进行连接
    - 各个存储用户记录的数据页根据用户记录最小的主键值大小排列成一个双向链表
    - 存放目录项记录的数据页分不同层次,同一层次的数据页根据页中目录项记录的主键值大小排列成一个双向链表
  2. 聚簇索引底层逻辑是B+树,且B+树的叶子结点存放的用户记录是完整的记录,即是我们认知中的数据表的一行

二级索引

聚簇索引是根据主键排序的,也就是说聚簇索引只能加快以主键为查询条件的查询语句,那么我要以非主键为查询条件时应该怎么办?可以使用二级索引。
二级索引根据指定列 + 索引进行排列,其有三个特点:

  1. 二级索引是根据指定列值大小进行记录和页的排序,这包含三个方面的意思:
    - 页内记录根据指定列值大小排序并使用单向链表进行连接
    - 各个存储用户记录的数据页根据用户记录最小的指定列值大小排列成一个双向链表
    - 存放目录项记录的数据页分不同层次,同一层次的数据页根据页中目录项记录的指定列值大小排列成一个双向链表
  2. 二级索引的用户记录存储的内容不是完整内容,是主键+指定列
  3. 二级索引的目录项纪录存储的内容是指定列+页号

由于二级索引的用户记录存储的不是完整信息,所以使用二级索引往往只是一个过渡,使用二级索引查询到对应的主键后,再使用主键进行聚簇索引查询,查询完整内容,这也是二级索引名称的由来,这个过程也称之为回表

查找过程:

  1. 现根据指定列的值查找到指定的目录项记录
    说明:一般目录项记录页只有一个,但也不排除以外的发生,可能全表的指定列的值都是一样的,这种极端情况只能采用其他索引了
  2. 根据指定列的值查找到指定的目录及录项,然后进入到对应用户记录页中查询数据
    说明:因为指定列的值不唯一,所以可能会有两个目录记录项都符合的情况,具体是什么情况可看下图
  3. 根据指定列的值找到对应的用户记录项(可能不唯一)
  4. 通过用户记录项得到对应的主键,在聚簇索引中通过主键查询到对应的完整记录

联合索引

之前两个说的都是单列查询索引,联合索引就是使用多列值进行排序的索引。
其和二级索引都差不多,只是在排列上不同而已,联合索引先根据指定列1进行排序,然后再对重复记录根据指定列2进行排序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值