MySQL高级-索引的数据结构

一、索引的引入

1. 什么是索引

索引是数据库存储引擎用来快速查找定位到数据的一种数据结构,索引是再存储引擎中实现的。所有存储引擎支持每个表至少16个索引,总索引长度至少为256字节。有些存储引擎支持更多的索引数和更大的索引长度。MySQL在查找数据的时候,首先会检测查询的条件是否有索引,如果有索引,则通过索引查找相关数据,如果没有用到索引,则进行表数据一条一条的全表扫描,直到找到符合条件的数据。索引就好比书籍中的目录,通过目录中的标题和页码,能快速的找到相关的文章内容。

2. 为什么使用索引

  • 在没有索引的时候,数据存放在磁盘是杂乱无章的,在查询数据的时候,一点规律的没有,查询时很耗时的。但是如果把这种杂乱的数据,进行有序排序之后,在查询数据的时候,就可以通过遍历列表就可以找到对应的数据。比如:想要查询【41】的数据,需要从89开始遍历,一条一条进行比较,直到【41】,才找到。这种数据少的时候还好,但是如果是上千条,上万条数据的话,时间复杂度O(n),此时就需要对有序的数据进行一个数据结构,降低查询的效率了。
    在这里插入图片描述

  • 如果把有序列表再转成二叉树的结构,二叉树的节点是以key-value的格式存放数据,key存的是具体的值,value存的是该值对应的文件地址指针。这样再进行查询【25】的时候,可以通过遍历二叉树的形式进行查询,【25】和【34】比较,发现小于【34】,往左节点走,【25】比较,发现等于,则返回数据。这样我们只要比较两次,就找到了数据,效率得到很大的提升。
    在这里插入图片描述

3. 索引的优缺点

3.1优点

  • 索引提高了数据查询的效率,较低了数据库IO的成本。
  • 创建数据表的唯一索引,可以保证数据表的每行数据的唯一性。
  • 在进行连表查询的时候,有效的提高了表与表之间的连接速度。
  • 在使用分组、排序查询的时候,给分组或排序字段建索引,可以减少分组或排序的时间,降低CPU的消耗。

3.2 缺点

  • 创建索引和维护索引,都需要消耗时间,随着数据量的增加,维护索引的时间也同步增加。在第一次创建索引的时候,会比较耗时的。
  • 索引是存放在磁盘上,索引索引也会占用一定的磁盘空间,如果有大量的索引,可能索引文件占用的磁盘空间,会大于数据占用的空间的。
  • 索引虽然提高了查询的效率,但是对赠、删、改的速度降低了,因为更新操作,需要去维护索引。

二、索引的演进过程

1. 索引的设计

比如现在我们有一张数据表:student(id,name,age),这个表使用 Compact 行格式来实际存储记录的。
在这里插入图片描述

  • record_type:位于信息头,表示记录类型,0-普通记录,1-目录项记录,2-最小记录,3-最大记录。
  • next_record:位于信息头,表示指向下一条记录的偏移量。
  • 其他信息:其他隐藏列的值以及记录的额外信息。

去掉【其他信息】后,将记录放到中:
在这里插入图片描述

2. 简化的页和记录

向表中插入几条数据,记录按主键顺序成功一个单项链表,id为主键:

INSERT INTO student(id,name,age) VALUES(1,'张三',23);
INSERT INTO student(id,name,age) VALUES(2,'李四',24);
INSERT INTO student(id,name,age) VALUES(3,'王五',25);
INSERT INTO student(id,name,age) VALUES(4,'赵六',26);
INSERT INTO student(id,name,age) VALUES(5,'宋七',27);

在这里插入图片描述
假设当前一个页最多能存放5条记录,然后我们再往表中插入数据时,由于页5存放不下,就会再分配新的页,这种情况称作页分裂
在这里插入图片描述
观察上图,我们发现页中的记录数,是通过单向链表进行有序的链接起来,而页与页之间,是通过双向链表链接起来的。页与页之间的编号也可能不是连续的,是通过维护上一个页和下一个页的编号建立的链表关系。

  • 有时候我们插入的数据id可能不是逐渐递增的,可能是:1,2,3,5,7这样的记录存放再页10中,当我们后面再添加一个id为4的时候,由于页中的记录是按主键递增的,所以页分裂的步骤为:
  1. 先分裂出页8,然后将id为4的数据存放到页8中,由于4小于【5,7】。
  2. 第二部是将记录【5,7】的记录移动到页8中,然后再将记录4移动到页5中。
  3. 最后才完成记录4的插入,这种就会出现记录移动
  • 通过这个过程,发现进行数据的增删改操作时,都需要通过记录移动来动态维护页记录。

3.建立目录项

当我们向数据表的数量量很之后,加载到内存的数据页就会很多,由于数据页的编号不是连续的,我们在查找记录所在的数据页时,非常困难。此时需要给数据页做一个目录,使数据页使有序的结构,这个目录就叫数据页的目录项
在这里插入图片描述
每个目录项都有两个部分组成:

  • key:存的使页中的最小记录的主键。
  • page_no:存的使页的编号。

4. 建立目录项的记录页

多个目录项也是存放再一个数据页中的,再进一步推演目录项:
在这里插入图片描述

  • 每个目录项之间也是通过单向链表进行连接的。
  • 目录项的头信息中,有record_type和next_record,只是目录项的record_type是1。
  • 目录项只有主键的主键的值和页编码列,而普通的记录有用户自定义的列,还有存储引擎的隐藏列。
  • 普通记录和目录项都是一样的数据页,都会为主键值生成页目录,从而再查询的时候,按主键值进行二分查找,增加了查找的速度。
  • 比如现在查找id为【9】的记录:
    1. 首先在目录项的页3中进行查找,使用的事二分法,快速定位:6<9<11,所以找到记录的页8
    2. 再去普通记录的页8中查找,通过二分法快速找到id为9的记录。

当有有多个目录项的数据页的时候,也是通过双向链的方式,将两个数据页连接起来,也是通过页的分裂来实现的。
在这里插入图片描述

5. 建立目录项记录页的目录页

我们的目录项的记录页跟普通记录的页一样的,页与页之间并不是连续的,那么当目录项的记录页很多的时候,我们又要怎么做才能使快速通过主键,使查询数据的熟读更快呢?
此时,又可以为这个存储目录项的页生成一个更高级的目录页,像大目录嵌套这下一级目录,最小的目录才是实际存放记录的数据页。
在这里插入图片描述
如上图,在目录项的目录页上面,生成了一个更高级的页【30】。此时在进行查找的话,查找的主键位于[1,11)之间,就走页3目录项的页,如果大于11的话,走页7目录项的页。
最后形成的这个数据结构,称为B+树
简化结构:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值