【MySQL】索引

目录

🌈前言🌈

[📁 索引](#📁 索引)

[📁 磁盘](#📁 磁盘)

[📁 Page](#📁 Page)

[📁 索引结构](#📁 索引结构)

[📂 B树 和 B+树](#📂 B树 和 B+树)

[📂 聚簇索引 和 非聚簇索引](#📂 聚簇索引 和 非聚簇索引)

[📂 回表查询](#📂 回表查询)

[📁 索引操作](#📁 索引操作)

[📂 主键索引](#📂 主键索引)

[📂 唯一键索引](#📂 唯一键索引)

[📂 普通索引](#📂 普通索引)

[📂 查询索引](#📂 查询索引)

[📂 删除索引](#📂 删除索引)

[📁 总结](#📁 总结)


🌈前言🌈

本期【MySQL】讲解MySQL中索引的概念,什么是索引,为什么要有索引,以及MySQL如何做到和磁盘交互,使得数据持久化,还将会展示MySQL索引的相关操作。

如果没有额外说明,默认采用的存储引擎是InnoDB。

📁 索引

在MySQL中,索引是一种特殊的数据结构,用来提高数据库查询的效率。

例如一本书,如果我们没有目录结构,那么我们想要确切的查询到某一个,是不是要线性遍历才能找到,效率非常低下,因此每一本书都有目录。在数据库中,数据都是保存在磁盘上的,因此想要查询某个数据是要进行IO的,如果我们使用线性遍历,那么IO次数会非常高,效率低下。索引就可以起到减少IO次数,提高效率的作用。

因此,索引就是数据库的一种数据结构,用来加速数据库检索操作,类似书籍目录。

索引的类型:

  • 主键索引:唯一标识每一行数据,且不允许有空值。
  • 唯一索引:确保索引列的值唯一,但允许空值。
  • 普通索引:没有唯一性限制,可以包含重复值。
  • 全文索引:主要用于文本搜索,支持对文本字段的高效查找。
  • 组合索引:由多个列组成的索引,能够加速基于这些列的查询

📁 磁盘

下面我们会简单介绍一下磁盘的概念,来引入MySQL如何与磁盘交互的概念。

本文只是简单介绍了磁盘,在下面这篇文章中,详细介绍了磁盘以及文件系统的概念。

【Linux杂货铺】文件系统-CSDN博客

数据库文件,本质就是保存在磁盘盘片当中,也就是扇区中。因此我们查找文件,就是查找到具体某个扇区。

  • 柱面(Cylinder):硬盘上的同一轨道在多个磁头上的垂直堆叠形成的圆柱形区域。每个柱面包含多个扇区。
  • 磁头(Head):用于读取或写入数据的机械部件。每个硬盘有多个磁头,通常对应于每个盘片的两面。
  • 扇区(Sector):硬盘上最小的数据存储单位,通常为512字节。

我们只需要知道,磁头(Heads)、柱面(Cylinder)(等价于磁道)、扇区(Sector)对应的编号,就可以定位要访问的扇区,这种磁盘数据定位方法叫做CHS。实际中我们通常使用LBA(逻辑区块地址法),它是一种线性地址,可以理解为虚拟地址和物理地址的区别。系统最终还会降LBA转换为CHS地址。

磁盘的基本单位是512B 。但是对于OS来说太小了,并且OS不能与磁盘具体的数值强相关,这会造成OS依赖于硬件,因此OS读取磁盘的基本单位是4KB

📁 Page

以上我们了解了磁盘,以及知道了磁盘的基本单位是512B,OS操作硬盘的基本单位是4KB。

MySQL作为一款软件,可以想象成一种特殊的文件系统*,有着更高的IO场景,为了提高基本IO的效率,MySQL进行IO的基本单位是16KB,这个基本数据单元,在MySQL中称为pape。

MySQL中的数据文件,是以page为单位保存在磁盘中的。MySQL通过page将数据保存在磁盘的过程中肯定设计计算,因此需要CPU的参与,这个过程CPU一定不能和磁盘进行直接交互(效率太低),因此MySQL会预先开辟好一段内存空间,进行缓存,之后通过缓存和磁盘数据进行IO。

  1. 缓冲池(Buffer Pool)

使用缓冲池来缓存数据页面,以减少磁盘的直接访问,提高性能。

当数据被插入,更新或删除时,相关的页面首先在内存中的缓冲池进行修改。

  1. 脏页(Dirty Pages)

当缓冲池的页面被修改后,这些页面称为脏页。脏页不会立即写入磁盘,而是保留在内存中,等待合适时机写入。

  1. 日志(Redo Log)

将脏页写入磁盘之前,InnoDB还会将更改记录到重做日志中,以便日后系统崩溃后可以修复数据。

  1. 写入策略

InnoDB使用"写回"策略,即在特定条件下将脏页写入磁盘:

  • 周期性检查:数据库系统会定期检查脏页的数量,并将它们写入磁盘。
  • 内存压力:当缓冲池中的内存空间不足时,系统会选择一些脏页写入磁盘,以释放空间。
  • 事务提交:当一个事务提交时,相关的脏页会被写入磁盘,以确保持久性。

我们需要将page管理起来,先描述,在组织的原则,我们可以将page理解为一个结构体对象,用双向链接表管理起来。

我们有了一个16KB的page,将数据保存在page中,如果我们要在单个page中查找,如何查找呢?

我们可以看到目前只能通过线性遍历的方法,效率还是太低了。因此,在单个page中我们引入了页目录的概念。

以上是在单个page中进行查找,如果我们有多个page呢?其实方法和页目录差不多。

我们可以创建一个新的page,这个page不用来存储数据,而是用来充当目录的作用。这样我们就可以通过几次的IO,找到具体的数据。大大提高了效率。

使用一个目录项来指向某一页,而这个目录项存放的就是将要指向的页中存放的最小数据的键值。

和页内目录不同的地方在于,这种目录管理的级别是页,而页内目录管理的级别是行。

其中,每个目录项的构成是:键值+指针。图中没有画全。

目录页的本质也是页,普通页中存的数据是用户数据,而目录页中存的数据是普通页的地址。我们每次检索数据的时候,该从哪里开始呢?虽然顶层的目录页少了,但是还要遍历啊?不用担心,可以在加目录页。

因此,最终得到的结果就是下图所示:

上述,我们就可以简单理了一下什么是B+树,即InnoDB的索引结构。

📁 索引结构

在 MySQL 中,索引结构是保存在文件中的,

  1. 索引文件

    • 对于不同的存储引擎(如 InnoDB 和 MyISAM),索引信息会保存在不同的文件中。
    • InnoDB 使用表空间文件(通常是 ibdata1 或者各个 .ibd 文件)来存储数据和索引。
    • MyISAM 存储引擎则将数据和索引分开存储,通常为 .MYD(数据文件)和 .MYI(索引文件)。
  2. 启动时的行为

    • 当 MySQL 启动时,它会读取这些文件,恢复到最后一次关闭时的状态,包括索引结构。
    • 如果没有任何更改(如没有执行 ALTER TABLE 操作等),索引在重启后依旧有效。
  3. 更新索引

    • 索引会随着对表数据的增加、删除或修改而自动更新。因此,任何对数据的更改都会影响相应的索引,但不需要每次启动时重新创建。

📂 B树 和 B+树

在了解B树之前,我们先来回顾一下数据结构,链表,二叉树搜索,哈希表,为什么都不行,而是采用了B树系列(本质是一个多叉树)。

链表的遍历就是线性遍历;二叉树搜索树,存在退化为线性遍历的可能;AVL树,红黑树,终究是一个二叉树,层数过高的时候,效率太低;MySQL 是支持HASH的,不过 InnoDB 和 MyISAM 并不支持.Hash跟进其算法特征,决定了虽然有时候也很快(O(1)),但在面对范围查找就明显不行。

B树:

B+树:

本质是B树的变形,非叶子节点不在存储数据,只有叶子节点存储数据,这样一个节点就可以存储更多的key。可以使得树更矮,所以IO操作次数更少 。叶子节点相连,更便于进行范围查找

📂 聚簇索引 和 非聚簇索引

MyISAM存储疫情同样使用B+树来索引结果,但是叶子节点data域不存数据本身而是数据记录的地址。

MyISAM 最大的特点是,将索引Page和数据Page分离,也就是叶子节点没有数据,只有对应数据的地址。 相较于 InnoDB 索引, InnoDB 是将索引和数据放在一起的。

MyISAM 这种用户数据与索引数据分离的索引方案,叫做非聚簇索引 ;InnoDB 这种用户数据与索引数据在一起索引方案,叫做聚簇索引

📂 回表查询

MySQL 除了默认会建立主键索引外,我们用户也有可能建立按照其他列信息建立的索引,一般这种索引可以叫做辅助(普通)索引。

但是在InnoDB引擎下,非主键索引中叶子结点并没有数据,而是对应记录的key值(主键)

因此需要两遍索引:首先通过辅助索引获得主键,在通过主键在主键索引中获得记录,这个过程就叫做回表查询。

在 InnoDB 中,如果表没有主键,仍然可以创建辅助索引,但会有一些影响和注意事项:

  • 如果没有定义主键,InnoDB 会自动为每个表创建一个隐藏的隐式主键,通常是一个 6 字节的内部行 ID。这意味着即使没有显式的主键,你仍然可以创建辅助索引。
  • 没有主键的表可能会导致性能问题,因为每次通过辅助索引查找数据时,都需要通过隐式主键进行回表查找。
  • 如果表数据很大,这种额外的查找可能会增加查询的开销。

📁 索引操作

索引创建原则:

  1. 比较频繁作为查询条件的字段应该创建索引

2 .唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件

  1. 更新非常频繁的字段不适合作创建索引

  2. 不会出现在where子句中的字段不该创建索引

📂 主键索引

创建主键索引:

sql 复制代码
1.
create table user1(id int primary key, name varchar(30));

2.
create table user2(id int, name varchar(30), primary key(id));

3.
create table user3(id int, name varchar(30));
-- 创建表以后再添加主键
alter table user3 add primary key(id);

主键索引特点:

1. 一个表中,最多有一个主键索引,当然可以使符合主键

2. 主键索引的效率高(主键不可重复)

3. 创建主键索引的列,它的值不能为null,且不能重复

4. 主键索引的列基本上是int

📂 唯一键索引

创建唯一键索引:

sql 复制代码
1.
create table user4(id int primary key, name varchar(30) unique);

2.
create table user5(id int primary key, name varchar(30), unique(name));

3.
create table user6(id int primary key, name varchar(30));
alter table user6 add unique(name);

唯一键索引特点:

  1. 一个表中可以有多个唯一键索引

  2. 查找效率高

  3. 如果在某一列建立唯一键索引,必须保证这个列不能有重复项

  4. 如果一个唯一键索引上指定not null,等价于主键索引。

📂 普通索引

创建普通索引:

sql 复制代码
1. 
create table user8(id int primary key,
    name varchar(20),
    email varchar(30),
    index(name) --在表的定义最后,指定某列为索引
);

2. 
create table user9(id int primary key, name varchar(20), email
varchar(30));
alter table user9 add index(name); --创建完表以后指定某列为普通索引

3.
create table user10(id int primary key, name varchar(20), email
varchar(30));
-- 创建一个索引名为 idx_name 的索引
create index idx_name on user10(name);

普通索引特点:

  1. 一个表中可以有多个普通索引,普通索引在实际开发中用的比较多

  2. 如果某列需要创建索引,但是该列有重复的值,那么我们就应该使用普通索引

📂 查询索引

sql 复制代码
1. 
show keys from 表名;

2.
show index from 表名;

3. 
desc 表名;

📂 删除索引

sql 复制代码
1. 删除主键索引
alter table 表名 drop primary key;

2. 其他索引的删除
alter table 表名 drop index 索引名;

3.
drop index 索引名 on 表名

📁 总结

以上就是本期【MySQL】索引的全部内容,讲解了索引概念,MySQL与磁盘的交互,以及B+树作为MySQL的存储结构,它的实现和优势,此外展示了索引操作的相关代码。

如果感觉本期内容对你有帮助,欢迎点赞,关注,收藏Thanks♪(・ω・)ノ

相关推荐
188号安全攻城狮24 分钟前
【PWN】HappyNewYearCTF_8_ret2csu
linux·汇编·安全·网络安全·系统安全
Tansmjs41 分钟前
使用Python自动收发邮件
jvm·数据库·python
m0_5613596743 分钟前
用Python监控系统日志并发送警报
jvm·数据库·python
Dxy12393102161 小时前
MySQL INSERT ... ON DUPLICATE KEY UPDATE 与非主键唯一字段
数据库·mysql
zhousenshan1 小时前
springboot事务管理几种方式
数据库
Yana.nice2 小时前
openssl将证书从p7b转换为crt格式
java·linux
布局呆星2 小时前
SQLite数据库的介绍与使用
数据库·python
AI逐月2 小时前
tmux 常用命令总结:从入门到稳定使用的一篇实战博客
linux·服务器·ssh·php
2401_838472512 小时前
用Python和Twilio构建短信通知系统
jvm·数据库·python
石头wang2 小时前
oracle jdbc 依赖以及对dbeaver的性能影响,如何选择oracle驱动, oracle jdbc 驱动
数据库·oracle