MySQL高级第一篇:索引的来源,优缺点及B+树的演化

  • 一、为什么使用索引?
  • 二、索引的优缺点?
  • 优点
  • 缺点
  • 三、InnoDB索引演化
  • 3.1. 索引之前的普通查找
  • 1. 假设表的数据不多,数据可以被放在一个页,根据条件搜索时,有两种情况:
  • 2. 大部分情况表中的记录比较多,需要分成多个页存储,这时查找记录分为两步:
  • 3.2 索引是怎么设计的?
  • 1. 目录项记录的页
  • 2. 多个目录项记录的页
  • 3. 目录页再抽取页
  • 4. B+树


一、为什么使用索引?

  • 索引是存储引擎用于快速找到数据记录的一种数据结构,在刚开始接触时,我们可以不严谨的把索引比作一本书的目录,通过目录可以快速定位到对应文章的页码。
  • 在MySQL中也一样,如果有了索引,就不用再一条一条的全表扫描了,大大提高查询效率。
  • 创建索引,目的就是为了减少磁盘I/O的次数,加快查询速率。

二、索引的优缺点?

优点

  • 提高检索效率,降低磁盘I/O
  • 唯一索引可保证数据的唯一性(唯一约束,自动添加唯一索引)
  • 对于有依赖关系的子表和父表联合查询时,可以提高查询速度
  • 在使用分组和排序查询时,可以减少分组和排序时间,降低了CPU的消耗

缺点

  • 创建维护索引耗费时间
  • 索引也需要存到磁盘上,占用磁盘空间
  • 修改表数据也需要维护索引,降低更新表的速度

三、InnoDB索引演化

3.1. 索引之前的普通查找

SELECT [列名] FROM 表名 WHERE 条件

注意:表中的数据以页为单位存储,每个页的默认大小为16KB

1. 假设表的数据不多,数据可以被放在一个页,根据条件搜索时,有两种情况:
  • 以主键作为搜索条件
  • 一般在添加数据时,主键为自增长,也就是说主键是递增有序的,这时可以使用二分法查找
  • 以其它列作为搜索条件
  • 这种情况下没有什么规律,只能从最小记录开始依次遍历单链表中的每条记录,效率较差。(表中每条记录是以单链表的形式存储的)
2. 大部分情况表中的记录比较多,需要分成多个页存储,这时查找记录分为两步:
  • 第一步:定位记录所在的页
  • 第二步:在所在页以情况一的方式搜索

在没有索引时,我们不能快速定位到所在的页,只能从第一页沿着双向链表一直往下找,在每一个页中匹配,这是一种效率低下的查找方式,也就是索引存在的意义了。

3.2 索引是怎么设计的?

假设现在有一张表,表中有C1,C2,C3三列,以Compact行格式保存,如下:

mysql 加索引的列不能为空吗 mysql为什么加索引_mysql 加索引的列不能为空吗


record_type:0表示普通记录;1表示目录项页;2表示最小记录;3表示最大记录所以,一个页的大概结构如下:

mysql 加索引的列不能为空吗 mysql为什么加索引_索引_02


当记录一个页放不下时,会存放在多个页中,以双向链表连接,但无论几个页,主键ID都要保持递增,如果插入顺序不是按递增主键插入,会发生记录移动,以保持这种结构,多个页中的这种行为称为页分裂。当多个页查询时,我们难以定位到数据在哪一个页,只能从第一页开始遍历,基于这种情况,考虑可以给所有的页建立一个目录项,让目录项连续依次递增,每个目录项记录页的最小记录和页号

mysql 加索引的列不能为空吗 mysql为什么加索引_B+树_03


这样,我们就可以利用二分法查询目录项,快速定位到某一页,再在这个页这种查询,这就是索引演化的雏形。

1. 目录项记录的页

我们在上边已经了解了索引的雏形,但是在实际操作中存在两点问题:

1,随着页的越来越多,目录项也越来越多,而目录项存储在连续的空间,页越来越多,空间压力也越来越大;
2,数据页的增删使得目录项也需要增删,很不方便

基于这种情况,考虑将目录项以单链表的方式存储,所有目录项也存储到一个页中,把它叫做目录页,如下:

mysql 加索引的列不能为空吗 mysql为什么加索引_索引_04

2. 多个目录项记录的页

随着数据页的越来越多,一个目录页放不下所有的目录项了,这时,就考虑将目录项放在多个目录页中,目录页之间逻辑连续,采用双向链表链接

mysql 加索引的列不能为空吗 mysql为什么加索引_mysql 加索引的列不能为空吗_05

3. 目录页再抽取页

当目录页超过一个时,定位数据页先遍历目录页,目录页越多IO次数越多,考虑给目录页再生成一个更高级的页,这个页可以连续,使用二分法更方便确定目录页

mysql 加索引的列不能为空吗 mysql为什么加索引_mysql_06

一步步演化到这里,这其实就是我们所谓的 B+ 树了

4. B+树

经过上边的演化,我们得出了 B+ 树的结构,简化来说如下:

mysql 加索引的列不能为空吗 mysql为什么加索引_mysql 加索引的列不能为空吗_07


需要注意,B+ 树的层次越低,IO次数越少,一般B+树不超过4层