【MySQL】索引(重要)

目录

一、索引本质:

索引的核心作用

索引的优缺点

二、预备知识:

硬件理解:

软件理解:

MySQL与磁盘交互基本单位:

三、索引的理解:

理解page:

单个page:

多个page:

聚簇索引 VS 非聚簇索引

回表查询:

四、索引实操:

创建主键索引:

创建唯一键索引:

创建普通索引:

创建复合索引:

删除索引:


一、索引本质:

索引是用来进行高效查询的,其本质上是数据库中的一种高效数据结构,其主要是B+树,它能够加快数据的查询,排序的类似操作,类似于书本的目录,是通过减少所需要扫描的数据来提高性能的,就像二分查找那样,在二分查找中,能够查找一个数据就能够去掉一半的无效数据,索引也是类似于如此,

但是索引也并不是没有代价的,查询速度是提高了,但是插入,更新,删除的效率会有所降低,这些写操作,增加了大量的IO,在调整的时候会对其底层的所实现的数据结构如B+树进行维护

索引的核心作用

  • 加速查询:通过跳过全表扫描,快速定位目标数据。
  • 排序优化:索引本身有序,可加速ORDER BY,GROUP BY等操作
  • 唯一性约束:唯一索引(如主键)确保列值的唯一性。

索引的优缺点

优点

  • 显著提升查询速度(尤其是大数据量)
  • 加速表连接(如外键索引)
  • 避免排序开销(索引已有序)

缺点

  • 占用额外存储空间
  • 降低写操作(INSERT/UPDATE/DELETE)速度,需维护索引结构
  • 索引设计不当可能导致未命中(如索引失效)

二、预备知识:

硬件理解:

MySQL给用户提供存储服务,是存储在磁盘上的,数据是存储在磁盘上的那一个个扇区中的, 关于磁盘的更详细了解可以看看我之前写的:

【Linux】基础IO------理解文件系统(inode)-CSDN博客https://blog.csdn.net/2303_80828380/article/details/144544294?spm=1001.2014.3001.5501理解:

在系统软件上,并不是按照扇区(512字节或者4096字节/4kb)进行交互的,因为这样的话就会和硬件强相关了,也就是如果将硬件换了就会导致系统软件也必须跟着变换,这样其耦合度就会太高,不便于彼此之间的硬件或者系统各自进行升级或者更新,所以必须得将解耦工作做得更好

并且,单词IO 512字节的单位太小了,IO单位小意味着读取相同的内容的会多次进行IO,这样导致每次IO都会将磁盘进行转动,磁头进行选扇区,这些机械操作就肯定会带来效率的降低

所以系统进行读取磁盘是以块为单位进行存储的,基本单位是4kb(4096字节),4kb是为了能够让磁盘数据和内存数据进行更好的IO交互

那么4kb会不会多做了很多工作呢?实际上单纯这样理解是不够充分的,因为OS一次加载4kb也有其自己的考量 -----局部性原理,实际上本身就是预加载,预加载数据也就是一次加载4kb,有可能只使用几条指令,但是后面的部分,可能也有些指令,大概率还会访问的,所以因为局部性原理,一次预加载4kb空间是能够在一定意义上在宏观的概率提高整体的效率的

软件理解:

MySQL与磁盘交互基本单位:

MySQL是属于在OS上的应用层中的,也就是说MySQL之下是OS,MySQL是通过OS和硬件打交道的,不能够直接和硬件打交道

在MySQL中,MySQL和磁盘打交道的单位是page---其大小是16kb,

如上,这是以字节为单位的,将value=16384进行 /1024 就是16kb

这看起来是MySQL直接和磁盘打交道的,但是实际上并不是如此,实际上是MySQL先要经过OS,然后在让OS和磁盘打交道,这里MySQL一次性操作就是16kb,但是到了OS就是4次4kb,但是我们不需要关心这4次4kb是怎么进行交互的

MySQL中的page和OS中的page是1:4的关系

buffer pool:

首先要知道,MySQL中的数据文件都是以page为单位保存在磁盘中的,当对MySQL中的表进行各种CRUD的时候,首先要通过计算找到对应的位置,既然要进行计算,就需要CPU进行参与,既然要CPU进行参与,根据冯诺依曼体系结构,我们知道CPU和内存打交道的,所以就需要将数据从磁盘中移动到内存中,在内存上完成数据的CURD后,在以特定的刷新策略从内存刷新到磁盘中,此时就是内存到磁盘之间的数据交互了,也就是IO,其基本单位是page在这里是以4kb为大小的

但是这样的话效率是比较低的,为了提高效率,当MySQL服务器在其内存中运行的时候,在其服务器内部申请了buffer pool的大内存空间,来进行缓存,这样MySQL就能够直接和buffer pool进行数据交互,不需要等待OS和磁盘进行IO交互

三个共识:

1、MySQL以16kbpage为单位进行MySQL级别的IO

2、MySQL有自己的buffer pool,MySQL在进行IO的时候,它会把读到的数据写到buffer里,刷新的时候,也是把buffer里的数据刷新到自己的OS内部的缓冲区中,最后在刷新到磁盘的

3、一般在进行IO的时候要减少OS和磁盘的IO次数,所以一次IO次数越大,那么它的IO次数越少,效率就会越高

三、索引的理解:

我们首先看一个现象,这里创建一个学生表,然后把id设置为主键,

接着在进行插入的时候故意乱序插入:

然后在进行查找:

这里发现尽管我们是乱序进行插入的,但是在查找的时候却是有序的,这显然只有是MySQL进行处理了的,但是MySQL为什么要这样进行处理呢?

要想知道,我们得先理解page

理解page:

如何理解MySQL中page的概念:

page只是一个个内存块么?

在MySQL内部一定会存在大量的page,那么就需要将这些大量的page通过B+树进行管理-----先描述,再组织,所以这些page内也会存在指向下一个page的指针,所以不能将page认为仅仅是一个内存块,page内部也必须写入对应的管理信息:

struct page
{struct page* next;struct page* next;char buffer[NUM];
}

那么为什么IO交互的单位是page呢?

这里为什么是通过以page为单位进行交互呢?为什么不用多少就申请多少呢?

因为存在局部性原理:CPU访问存储器时(包括指令和数据),所访问的地址倾向于聚集在较小的连续区域内,而非均匀分布

比如我们要查找学号为3的学生,就需要从学号为1的学生依次进行查找,这里就需要进行3次IO,那么如果是学号为5呢?50呢?500呢?这样就会进行很多次IO,那么如果将学号为5的学生都保存在同一个page中,在MySQL中一个page交互为16kb是很大的空间,能够保存很多记录,这时如果在查找学号为2的学生后,如果想查找学号为5或者在同一个page中的学生的学号的时候,就不需要进行IO了,直接读取即可,这样就能够大大减少IO的次数

但是怎么保证下次找到数据一定在同一个page呢?这是不能够严格保证的,但是因为存在局部性原理,会有很大的概率

这样因为IO次数的减少就能够提高IO的效率,因为往往IO效率的低下并不是IO单次的数据量,而是IO的次数

单个page:

通过上述分析,我们知道要管理好表的数据文件,我们目前可以理解这一个个文件是由一个或多个page构成的

所以其可以理解为:

在page里面,当进行数据的查找的时候,如果进行链式查找的话效率会很低下,所以page里面并不全是数据,还牺牲了一小部分的空间来存放目录,

这样当进行查找的时候就不从数据的最开始直接进行链式查找了,而是通过目录进行查找,这样的话能够大大增大效率

那么回到我们之前的问题,为什么乱序插入,MySQL会通过我们的主键进行排序呢?

这是因为要引入目录,那么就需要数据的有序性,这样方便通过目录进行查找

多个page:

当创建一个表的时候,这个表中所需的数据可能会很大,所以就需要多个page,那么我们解决了单个page的查找效率问题,但是多个page的查找效率问题呢

如果有多个page,并且在查找数据的时候,数据在最后一个page中,这个时候进行线性遍历的话需要遍历所有page,这个遍历操作是在内存中进行的,那么就需要将所有page从磁盘中IO交互到内存中,会增加IO次数,进而影响效率

如果仅仅给单个page加上目录有点杯茶水车薪了,所以就需要给所有page加上目录,进而大大提高效率

那么就需要创建目录page,这个page里面只存其管理的page的最小主键所对应的数据,如下就是示意图,最下面的就是里面有数据的page,然后上一层就是只存放目录的page,

当数据进一步增多,那么就需要再加上一层page了,这样就能够很快速的读取数据了

这就是一颗B+树,这是多叉树的结构,是innodb下的索引结构,当进行查找的时候就会首先在最上面的page中查找到一个范围,这样就会淘汰掉很多数据,像上述那样,仅仅只有三层但是其能够存储2000多万条数据了

这样当进行IO查找的时候,就仅仅只需要进行磁盘和内存之间交互3次即可

关于这可B+树:

1、叶子结点保存了数据,非叶子节点没有保存数据,只保存了目录,这是为了让非叶子节点存储更多的目录这样来管理更多的叶子page,对与这棵树其外形就是一棵矮胖型的树,这样就能够使其途径的节点数量少,只需通过更少的page,更少的IO来找到数据,这样大大提高了效率

2、叶子节点是全部用链表连接起来了,这是B+树的特点,并且这样能够便于进行范围查找

3、我们进行建表插入数据的时,就是在这棵B+树下进行CURD的,在进行目录的引入的时候,在之前的学习中我们了解需要让这些数据是有序的,就需要主键,但是如果我的表没有设置主键呢?那么会不会就是乱序的,这是不会的,尽管我们没有主动设置主键,但是MySQL会设置默认主键

4、MySQL底层会将我们的数据组合成这个B+树的,然后将其保存在buffer pool中,MySQL中会有大量的表被处理,所以在buffer pool中就会有多个索引结构,也就是存在多个B+树

5、为什么使用B+树,不使用B树或者其他数据结构呢?

链表:不行,这是链式存储,查找的效率低下

二叉树,AVL树,红黑树,这都是二叉式的结构,是瘦高型的树,其效率不如矮胖型的B+树,并且二叉树在极端情况下会退化为链式结构

B树也不行,B树不只是在叶子结点中进行数据的存储的,还有在非叶子节点中也会存储数据的,这样会导致范围查找不如B+树,哈希表这个数据结构也是因为范围查找不行而不被使用的

聚簇索引 VS 非聚簇索引

像上述所讲的那种将数据和索引都放在叶子结点中这种存储方式是我们innodb的存储形式

与这种不同的是Myisam引擎的底层,并未将索引和数据放在一起,其叶子节点存储的只是数据的地址,然后通过这个地址进行数据的查找的

如下:

  • 将B+树和数据本身分离的方案称为非聚簇索引
  • 将数据和B+树放到一起的称为聚簇索引

接下来看例子:

如上,通过innodb引擎和Myisam引擎创建两张表

我们是通过MySQL客户端进行创建的表,接着MySQL服务端就会将我们创建的表在磁盘中创建对应的文件.

其中test1也就是innodb只有一个文件ibd,索引和表是合起来的

其中test2这两个文件里面myd就是数据,myi就是索引结构

所以innodb为聚簇索引,Myisam为非聚簇索引

回表查询:

MySQL除了会建立主键索引外还会建立不止一种索引,其他的索引叫做普通(辅助)索引

对于Myisam,建立辅助索引和主键索引没有区别,唯一就是主键索引不能重复,非主键索引不能重复

对于Innodb,辅助索引就很有用了,辅助索引不在保存一个完整的数据了,而是只保存该表中的某一个字段和主键,比如保存的是主键和name列,未来查询某一个name信息,然后筛选条件是age,那么就会找到以这个age为key的辅助索引,然后就能够找到对应的主键了,然后就拿着这个主键,在主键索引中找到对应的name信息了

当根据普通索引查询数据时,会先查找普通索引对应的B+树找到目标记录的主键值,然后再查找主键索引对应的B+树找到目标记录,这个过程就叫做回表查询

索引的本质,就是一种数据结构

四、索引实操:

创建主键索引:

创建主键索引和创建主键的方式是一样的,在我们以前创建主键的时候不仅仅是创建了主键,并且还创建了主键索引

用如下SQL语句来进行查看

show index from 表名

或者也可以使用如下的两种方法,其实就是创建主键的方法:

create table 表名(id int, name varchar(20), primary key(id));create table 表名(id int, name varchar(20));
// 创建表以后再添加主键
alter table 表名 add primary key(id);

主键索引的特点如下:

  • 一个表中,最多只能有一个主键索引,一个主键可以由多个列同时承担。
  • 主键索引的查询效率高。
  • 创建主键索引的列,其列值不能为NULL,且不能重复。
  • 主键索引的列一般是数字类型。

创建唯一键索引:

alter table 表名 add unique(列名);

其实也就是创建唯一键的三种方法

create table 表名(id int primary key, name varchar(30) unique);create table 表名(id int primary key, name varchar(30), unique(name));create table 表名(id int primary key, name varchar(30));
alter table 表名add unique(name);

唯一索引的特点如下:

  • 一个表中,可以有多个唯一索引,一个唯一键可以由多个列同时承担。
  • 唯一索引的查询效率高。
  • 创建唯一索引的列,其列值可以为NULL,但是不能重复。
  • 如果给唯一索引设置NOT NULL属性,则等价于主键索引。

创建普通索引:

create table 表名(id int primary key,name varchar(20),email varchar(30),index(name));create table 表名(id int primary key, name varchar(20), email varchar(30));
alter table 表名 add index(name);create table 表名(id int primary key, name varchar(20), email varchar(30));
create index 自己取名字 on 表名(name)
create table test(id int primary key,name varchar(20),ema,email varchar(30),index(name));

创建复合索引:

首先将name的普通索引删除

alter table test1 add index(name, email);

如上,以name和email作为索引进行创建

接着会看到三个索引,这实际上是两个,只是name和email公用同一个B+树

删除索引:

删除主键索引:

alter table 表名 drop primary key;

删除非主键索引:

alter table 表名 drop index 索引名;drop index 索引名 on 表名;

一个表只有一个主键索引,所以在删除主键索引的时候不用指明索引名,而一个表中可能有多个非主键索引,所以在删除非主键索引时需要指明索引名

创建索引原则:

  • 比较频繁作为查询条件的字段应该创建索引。
  • 唯一性太差不适合做索引。
  • 更新太频繁不适合做索引。
  • 永远不会出现在where子句中的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/78442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【深入浅出MySQL】之数据类型介绍

【深入浅出MySQL】之数据类型介绍 MySQL中常见的数据类型一览为什么需要如此多的数据类型数值类型BIT(M)类型INT类型TINYINT类型BIGINT类型浮点数类型float类型DECIMAL(M,D)类型区别总结 字符串类型CHAR类型VARCHAR(M)类型 日期和时间类型enum和set类型 …

数字化时代下,软件测试中的渗透测试是如何保障安全的?

在如今数字化与信息化的时代,软件测试中存在渗透测试,其位置十分重要,它借助模拟恶意攻击的方式,去发现软件系统所存在的漏洞以及安全问题,这是保障软件安全的关键环节,接下来我会对它的各个方面进行详细介…

Pytorch - Developer Notes 1/2

文章目录 自动混合精度示例典型的混合精度训练处理未缩放梯度梯度裁剪 处理缩放梯度梯度累积梯度惩罚 处理多个模型、损失函数和优化器多 GPU 工作环境下的注意事项单进程中的DataParallel分布式数据并行:每个进程对应一个GPU每个进程使用多块GPU的DistributedDataP…

RuntimeError: CUDA error: __global__ function call is not configured

表明在 CUDA 设备上调用的核函数 没有正确配置线程块和网格维度。 一般体现在: 直接调用 kernel 函数,而不是通过 launch 函数 指定 kernel 函数调用 解决方法(示例): // kernel function __global__ void Idtest_k…

cloudfare+gmail 配置 smtp 邮箱

这里介绍有一个域名后,不需要服务器,就可以实现 cloudfare gmail 的 邮箱收发。 为什么还需要 gmail 的 smtp 功能,因为 cloudfare 默认只是对 email 进行转发,就是只能收邮件而不能发送邮件,故使用 gmail 的功能来进…

如何在 CentOS 7 命令行连接 Wi-Fi?如何在 Linux 命令行连接 Wi-Fi?

如何在 CentOS 7 命令行连接 Wi-Fi?如何在 Linux 命令行连接 Wi-Fi? 摘要 本教程覆盖如何在多种 Linux 发行版下通过命令行连接 Wi-Fi,包括: CentOS 7、Ubuntu、Debian、Arch Linux、Fedora、Alpine Linux、Kali Linux、OpenSU…

基于PHP的在线编程课程学习系统

有需要请加文章底部Q哦 可远程调试 基于PHP在线编程课程学习系统 一 介绍 在线编程课程学习系统基于原生PHP开发,数据库mysql,前端jquery.js。系统角色分为学生,教师和管理员。(附带参考设计文档) 技术栈:phpmysqljquery.jsphps…

PyTorch_张量形状操作

搭建模型时,数据都是基于张量形式的表示,网络层与层之间很多都是以不同的shape的方式进行表现和运算。 对张量形状的操作,以便能够更好处理网络各层之间的数据连接。 reshape 函数的用法 reshape 函数可以再保证张量数据不变的前提下改变数…

大模型实践:图文解锁Ollama在个人笔记本上部署llm

使用在线模型服务时,我们常常需要支付API调用费用,这对于个人开发者或小型组织来说可能是一笔不小的开支。那么,有没有方法可以在本地免费使用这些强大的模型呢?答案是肯定的——Ollama就是这样一个工具。 当然如果是比较大的组织…

Python基本语法(lambda表达式)

lambda表达式 lambda的一般形式是在关键字lambda后面跟一个或多个参数,之后再紧跟一个 冒号,接下来是一个表达式。lambda是一个表达式,而不是一个语句,它能够出现 在Python语法不允许def出现的地方。作为表达式,lambd…

【MySQL数据库】用户管理

目录 1,用户信息 2,创建/删除/修改用户 3,数据库的权限 MySQL数据库安装完之后,我们最开始时使用的都是 root 用户,其它用户通常无法进行操作。因此,MySQL数据库需要对用户进行管理。 1,用户…

Python的ArcPy基于Excel表格对大量遥感影像批量重分类

本文介绍基于Python中的ArcPy模块,以Excel表格内的信息,对遥感影像加以重分类的方法。 首先,明确一下本文的需求。现有按照文章ArcPy批量将栅格文件的属性表导出为Excel表格的方法(https://blog.csdn.net/zhebushibiaoshifu/artic…

LabVIEW 中VI Server导出 VI 配置

该 LabVIEW VI 展示了在 VI Server 中配置和执行 Exported VIs 的过程,实现对服务器端导出 VI 的远程调用与操作。 ​ 具体过程及模块说明 前期配置:需确保在 LabVIEW 的 “Tools> Options > VI Server > Protocols” 路径下,启用 …

论文阅读:2024 ACM SIGSAC Membership inference attacks against in-context learning

总目录 大模型安全相关研究:https://blog.csdn.net/WhiffeYF/article/details/142132328 Membership inference attacks against in-context learning https://arxiv.org/pdf/2409.01380 https://www.doubao.com/chat/4030440311895554 速览 这篇论文主要研究了…

从 Python 基础到 Django 实战 —— 数据类型驱动的 Web 开发之旅

主题简介: 本主题以 Python 基础数据类型为核心,结合 Django 框架的开发流程,系统讲解如何通过掌握数字、字符串、列表、元组、字典等基础类型,快速构建功能完善的 Web 应用。通过理论与实践结合,帮助学员从零基础 Py…

软考 系统架构设计师系列知识点之杂项集萃(53)

接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(52) 第85题 在静态测试中,主要是对程序代码进行静态分析。“数据初始化、赋值或引用过程中的异常”属于静态分析中的()。 A. 控制流分析 B. 数据…

Raycaster光线投射

Raycaster光线投射 3D虚拟工厂在线体验 描述 光线投射Raycaster,用于进行raycasting(光线投射)。 光线投射用于进行鼠标拾取(在三维空间中计算出鼠标移过了什么物体)。 构造器 Raycaster( origin : Vector3, dire…

初识Linux —— git三板斧

版本控制器git 为了我们方便管理不同版本的文件,就有了版本控制器; 所谓的版本控制器,就是能够了解到一个文件的历史记录(修改记录);简单来说就是记录每一次的改动和版本迭代的一个管理系统,同…

用哈希表封装出unordered_set/_map

前提: ①:本博客是对哈希表(开散列)进行封装,因为闭散列不优秀(与库保持一致) ②:哈希表封装出unordered_set/_map和红黑树封装出ste/map是大同小异的,可以先看下:用红黑树封装出set和map -CSDN博客 ③&…

情绪ABC——AI与思维模型【93】

一、定义 情绪ABC思维模型是一种心理学上的理论,它认为人们的情绪和行为反应(C,Consequence)并非直接由激发事件(A,Activating event)引起,而是由个体对激发事件的认知和评价所产生…