【Mysql】——索引的深度理解

阅读 115

2022-07-27

目录

一. 什么是索引?

二. 认识MySQL的存储

1.理解磁盘

2. MySQL与磁盘交互的基本单位

总结

三. 数据页(page)

1. 理解单个数据页

2. 理解多个数据页

四. 索引的分类

1.按结构分类

2.聚簇索引

3.非聚簇索引

实验

4.按字段特性分类

主键索引

 唯一索引和普通索引(二级索引)

普通索引与主键索引的区别 

 查询索引


一. 什么是索引?

索引是创建在数据表上的,是对数据库表中的一列或多列的值进行排序的一种结构。

如果将数据库比作一本书,那么索引就是书的目录,用来提高插叙的速度,通过索引,查询数据时可以不必读完记录的所有信息,而只是查询索引列。否则,数据库系统需要读取每条记录的所有信息进行匹配。

二. 认识MySQL的存储

1.理解磁盘

MySQL给用户提供存储服务,而存储的数据都是磁盘这个外设当中,磁盘是计算机的一个机械设备,相比于计算机其它电子元件,磁盘效率是比较低的,在加上IO本身特征,可以知道,如何提高效率,是Mysql重要的一个特征。

因此认识Mysql的存储,我们需要从磁盘开始认识:

 接下来我们研究其中一个盘面:

 数据库文件是保存在磁盘上的一个一个的扇区,也就是上面的一个一个的小格子,每个扇区大概是512个字节,当数据库文件很大,则会占用多个扇区。

 因此,查找一个文件,本质是在磁盘中找到该文件存储的扇区,而我们能够定位任何一个扇区,那么便能找到所有的扇区,因为查找的方式是一样的.那么怎样去定位扇区呢?

 

  • 柱面(磁道): 多盘磁盘,每盘都是双面大小完全相等。那么同半径的磁道,整体上便构成了一个柱面
  • 每个盘面都有一个磁头,那么磁头和盘面的对应关系便是1对1的。
  • 所以,我们只需要知道,磁头(Heads)、柱面(Cylinder)(等价于磁道)、扇区(Sector)对应的编号。即可在磁盘上定位所要访问的扇区

我们能够在硬件上定位任何一个扇区,但是在系统软件上,是按照扇区的大小(512个字节,少部分4096个字节),进行IO交互吗?

2. MySQL与磁盘交互的基本单位

系统与磁盘进行I/O的基本单位是4kb,但是MySQL作用一款存储软件,它的功能主要是增删查改,所以这就要求它有更高的I/O效率,就需要减少磁盘查找扇区的次数,因此MySQL进行IO的基本单位是16kb,这里叫做page。

当然,MYSQL作为一款应用软件,它是运行在用户区上,它不会直接与磁盘进行数据交互,只能是操作系统将数据读取到内核缓冲区中,然后MySQL在与内核缓冲区进行IO交互。

为什么MySQL的I/O的基本单位是page?

 但是我们忽略内核缓冲区与磁盘的IO交互,想象MySQL与磁盘进行IO交互,那么MySQL的数据文件是以page于磁盘进行I/O交互。

总结

  • MySQL是以page为单位保存与磁盘进行I/O交互,目的是为了提高I/O效率。
  • MySQL中的CRUD操作(增删查改),都需要通过计算,找到相对应的page的位置。
  • 只要参与计算,就需要CPU参与,而为了便于CPU,就需要先将数据移动到内存当中。这就涉及到磁盘与内存的IO交互,此时的IO的基本单位就是page。
  • 磁盘与内存的I/O时间=等的时间+拷贝的时间,在MySQL与磁盘的IO大部分时间都是在等,因为磁盘需要给你找到一个一个的磁道,在找到对应的扇区。
  • 记录是按照行来存储的,但数据库的读取并不以[行]为单位,否则一次读取(也就是一次I/O操作,只能处理一次数据,所以每次读取就需要进行一次I/O,查找效率低下。
  • 而数据库的I/O操作最小的单位是page,InnoDB 数据页的默认大小是 16KB,意味着MySQL每次到磁盘中读取的数据最少是16kb,刷新到磁盘上也是16kb。

三. 数据页(page)

1. 理解单个数据页

  • 每个数据页中的头部包含page_prevpage_next,分别指向前一个数据页和后一个数据页。
  • 每个数据页中包含页目录,方便查找页里面的数据
  • 数据页中的存储数据用了链表的结构,前一条数据指向下一条数据,方便数据的增加和删除。

下面是一个单个数据页的结构

 为什么要有页目录?

2. 理解多个数据页

如果有大量数据,则需要有多个数据页来存储这些数据,如果有多个数据页,同样需要给page带上目录,方便定位到相对应的数据页

  • 使用一个目录项来指向某一页,而这个目录项存放的就是将要指向的页中存放的最小数据的键值
  • 和页内目录不同的地方在于,这种目录管理的级别是页,而页内目录管理的级别是行
  • 其中,每个目录项的构成是:键值+指针。图中没有画全

 

 目录页是专门来存放指向page中的最小的数据和page地址,它本身不存放数据,当有多个目录页,如果要查找id为22的所有信息(id是主键),它的搜寻过程如下:

  • 通过”id=22“从在目录页中进行比较,发现它的id属于21这一页.
  • 通过指针找到21这一页,然后再去该页的目录进去查找,发现在目录三中。
  • 通过页目录3找到id为21的值,从id为21往下找,直到与id为22相对应。
  • 最后显示id=22的所有信息。

如果有多个目录页,则需要在创建一级目录页去管理这些目录页。

 

 如上是MySQL存储数据的整体结构,整体结构就是我们常说的B+树

如上树,如果我们刚开始要在MySQL中查找一个id值为1,它的查找过程:

  • 那么首先会先将b+树的根节点的目录页加载到内存当中
  • 再通过id=1找到下一级的目录页,并加载到内存当中。
  • 再通过目录页找到相对应的数据页,并加载到内存当中,并可以查找到相对应的值。

如上的过程加载了两次页目录,和一次数据页到内存中,一共进行了3次I/O.整个过程的I/O次数相对较少,因此可以提高搜索效率。

在内存当中是否为一整棵B+树?

 InnoDB采用的是B+树来作为索引,B+树它的特点有:

  • 只有叶子节点才会存储数据,非叶子节点仅用来存放目录项作为索引。
  • 非叶子节点分为不同层次,通过分层来降低每一层的搜索量。
  • 所有节点按照索引键的大小排序,构成一个双向链表,便于范围查找。

为什么不用B树来作为索引结构:

  • 相比于B+树来说,B树的节点里面既有数据,又有指针,由于数据页的大小是固定的,所以节点存储的索引就会减少,那么B树的高度就相对较高,如果结构是B树的话,那么在查找的时候,进行I/O的次数相对来说会比较多。
  • B+树的叶子节点全部相连,可以便于范围查找,而B树没有进行相连。

为什么不选用AVL树或者红黑树来作为索引结构?

四. 索引的分类

1.按结构分类

按结构分类有聚簇索引非聚簇索引

2.聚簇索引

用户数据和索引数据存放在一颗树上的方案称为聚簇索引。

 如上,非叶子节点存放的是索引值,叶子节点存放的是MySQL中的数据。

InnoDB存储引擎采用的采用的就是聚簇索引结构。

3.非聚簇索引

非聚簇索引就是数据与索引分开叶子节点存放的数据的地址,数据存放在另一张表中。如下:

 

MyISAM存储特点就是非聚簇索引,它的叶子节点只存放数据的地址,通过地址在去另一张表里面找到相对应的数据。

实验

在数据库中创建一个存储引擎为MyISAM的表结构mtest。

mysql> create table mtest
    -> ( id int primary key,
    -> name varchar(12) not null
    -> )engine=MyISAM;
Query OK, 0 rows affected (0.01 sec)

查看Mysql数据库目录路径,进入/etc/my.cnf文件 -> datadir=数据库的路径

[root@iZwz97d32td9ocseu9tkn4Z mysql]# vim /etc/my.cnf

进入mysql数据库 

[root@iZwz97d32td9ocseu9tkn4Z ~]# cd /var/lib/mysql

查看mtest文件,MyISAM存储引擎结构为有3个文件进行存储。

  • mtest.frm为表结构。
  • mtest.MYD为对应的数据,当前没有数据,所以是0。
  • mtest.MYI为对应的主键索引。

创建一个存储引擎为InnoDB的表结构,表名为innodb_test. 

查看 innodb_test表结构

 innodb_test.frm 表结构

 innodb_test.ibd 索引和用户数据。

4.按字段特性分类

按字段分类,有主键索引唯一键索引普通索引

主键索引

创建主键索引:

创建表的时候,直接在字段后面加上primary key

mysql> create table user1
    -> ( id int primary key,
    -> name varchar(12)
    -> );
Query OK, 0 rows affected (0.09 sec)

 唯一索引和普通索引(二级索引)

唯一键索引:一张表可以有多个唯一索引,索引列为空,但是允许有空值。

创建唯一索引,将id设置为唯一键索引:

mysql> create table user2(
    -> id int unique,
    -> name varchar(12)
    -> );
Query OK, 0 rows affected (0.02 sec)

普通索引与主键索引的区别 

InnoDB存储结构是聚簇索引,InnDB建立主键索引和普通索引的区别:

  • InnoDB的主键索引的B+tree的叶子节点存放的实际数据,所有完整的用户记录都存放在主键索引的B+Tree 的叶子节点里
  • 普通索引的B+tree的叶子节点存放的是主键值,而不是实际数据。

所以,在查询数据使用普通索引查找,如果查询的数据能够在普通索引树里面查询的到,则不需要回表,这个过程就是索引覆盖。如果查询的数据不在普通索引树里面,则会在普通索引中查找它的主键值,然后在通过主键值,再去主键索引树去查找,这就叫做回表查找

普通索引查找信息的过程:

  • 通过name为张飞在普通索引中查找相对应的主键值24,然后通过该主键值24再去主键索引查找张飞的所有信息,如下:

MyISAM的存储结构是非聚簇索引,它的普通索引与主键索引是没有差别。

它们的索引树都是存放存放的是数据的地址,然后通过数据的地址找到相对应的值。

 

 查询索引

 索引的创建原则

  • 比较频繁作为查询条件的字段应该创建索引
  • 唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
  • 更新非常频繁的字段(增删查改)不适合作创建索引
  • 不会出现在where子句中的字段不该创建索引

精彩评论(0)

0 0 举报