MySQL重难点(一)索引

目录

一、引子:MySQL与磁盘间的交互基本单元:Page

1、重要问题:为什么 MySQL 每次与磁盘交互,都要以 16KB 为基本单元?为什么不用多少加载多少?

2、有关MySQL的一些共识

3、如何管理 Page

3.1  单个 Page (数据页)内部是如何管理数据的?

3.2  多个 Page数据页之间又是怎么迅速找到数据对应页的呢

二、正式介绍索引

1、B+树 和 B树

2、常见的索引种类

2.1  主键索引

2.2  唯一索引

2.3  普通索引(用的较多)

2.4  全文索引

3、非聚簇索引 VS 聚簇索引

3.1  非聚簇索引:MyISAM存储引擎下与InnoDB 存储引擎非主键索引下的索引方案

3.1.1 MyISAM存储引擎下的非聚簇索引

3.1.2  InnoDB存储引擎下的非主键索引

3.2  聚簇索引:InnoDB存储引擎下的主键索引方案

4、索引的操作

4.1  索引的创建原则

4.2  查看表中的索引信息

4.3  删除索引

5、组合索引(复合索引、联合索引)

5.1  组合索引最左匹配原则

5.2  索引覆盖


索引是一个单独存储在磁盘上用于提高数据库查询效率的数据库结构,包含着对数据表里所有记录的引用指针。

使用索引可以快速找出在某个 / 多个列中某一特定值行,所有MySQL列类型都可以被索引,对相关列使用索引也是提高查询操作速度的最佳途径。

索引的底层有两种实现方案,B+树和哈希表,大部分MySQL存储引擎都使用B+树比如 InnoDB 存储引擎。笔者学习 MySQL 时,也学习的是 InnoDB 存储引擎下的MySQL;故本章也就着重介绍InnoDB 存储引擎下的索引机制。

一、引子:MySQL与磁盘间的交互基本单元:Page

MySQL 作为一款应用软件,可以把它视作一个特殊的文件系统,为了提高基本的IO效率,MySQL以 16KB 为基本单位与磁盘进行数据间的交互,这个 16KB 基本单元,被称作 Page。

(真实情况其实是操作系统以 4KB 文件块 为单位进行读取磁盘中的数据,放入自己内存的文件缓冲区内,MySQL 向操作系统申请数据,每单位申请 4 块,也就是 16KB) 

1、重要问题:为什么 MySQL 每次与磁盘交互,都要以 16KB 为基本单元?为什么不用多少加载多少?

假设 MySQL 要查找一个表中 ID=5 的数据,如果用多少加载多少,就需要与磁盘交互五次才能找到,而如果以16KB为单元进行交互,查找这个数据就只需要交互一次,剩下的查找都只在内存中进行,可以大大减少 IO 次数。

造成数据库查询效率低下的主要原因往往不是 IO 交互的单次数据量大小,而是 IO 次数,毕竟是两个计算机硬件间的交互。

2、有关MySQL的一些共识

1、MySQL 中的创建(Create)、更新(Update)、读取(Load)、删除(Delete)(简称CURD)操作,一定是需要通过CPU计算来找到操作位置的。

2、在Linux系统编程专栏中,我们可以知道,CPU只和内存交互,因此磁盘中的数据文件也势必要先加载到内存当中。因此在某段时间内,一定是磁盘和内存同时拥有数据文件,内存中对数据文件进行操作后,再刷新到磁盘上。涉及到磁盘与内存之间的交互,也就是 IO 了。

3、为了更好的进行上述操作,MySQL 服务器在内存中运行的时候,会提前申请一块大的内存空间(Buffer Pool,默认128MB),用于内存和磁盘间的IO交互。因此,我们想要提高数据库查询效率,就一定要尽可能减少 IO 交互次数。

4、MySQL 中的数据文件,都是以 Page 为基本单位存储在磁盘中的;一个 Page 大小为 16KB,MySQL内部一定会存在大量的 Page,这就意味着MySQL必须对 Page 进行管理,不能视作一个个零散的内存块。那么如何管理呢?

3、如何管理 Page

3.1  单个 Page (数据页)内部是如何管理数据的?

我们先给个例子:

create table if not exists user
(id int primary key,		-- 添加主键(后文会说,此时数据库会自动帮我们生成主键索引)age int not null,name VARCHAR(16) not null
);-- 我们是乱序插入的,并没有按照主键的顺序插入
insert into user(id, age, name) values(3, 18, '杨过');
insert into user values(4, 16, '小龙女');
insert into user(id, age, name) values(2, 26, '黄蓉');
insert into user(id, age, name) values(5, 36, '郭靖');
insert into user(id, age, name) values(1, 56, '欧阳锋');

运行后我们发现,表按照主键帮我们排序好了

为什么要排序好呢?

为了提高查询效率。因为数据页内部存放的一行行数据,实际上是一个链表结构

每个 Page 内部是个页表结构,本身也属于链表的一个节点,多个 Page 之间互相连接

而链表的特点是增删的时候快,但是查询速度比较慢。

为了改善查询速度,我们可以发现,Page 中除了数据记录,还有一个目录——这个目录就和平常书上的目录相似,记录着关键字的名称和其对应的地址(在这里,关键字是主键,记录着的就是主键的值和其对应的地址,也可以是唯一键或者其他的)

目录需要有序,所以要把数据按照关键字进行排序,这样目录就可以使用更加高效的查找算法(比如二分)来迅速定位数据

3.2  多个 Page数据页之间又是怎么迅速找到数据对应页的呢

单个数据页内部有目录,而多个数据页之间是用链表相连,我们自然可以想到,如果多个数据页之间的查找是线性遍历,那么单个数据页内部的目录就显得杯水车薪了,因此多个数据页相连的链表上层,还有目录页,然后多个目录页之间也是链表结构,层层往上都是类似。

目录页管理级别是页,数据页管理级别是行,目录页每个目录项构成是键值+指针

数据页中的存着用户数据,目录页中存着数据页的地址,每一个节点对应一个数据页,存放着这个个数据页最小数据行的关键字和这个数据页的地址。 

如果再层层往上,直至顶层,就会是这样的结构:

可以发现,是个B+树

这个结构,是B+树结构,也就是 InnoDB 存储引擎下的MySQL索引结构,通过这个结构,就可以大幅提高数据库查询效率

二、正式介绍索引

1、B+树 和 B树

可以发现,B+树实际上是一种多叉树

除了B+树,其实还有一种B树

 

我们可以发现,B树与B+树最大的区别就是:

B树的每一层的每一个节点都是既存有数据,又存有下一层页的地址,而且叶子结点并不相连;

而B+树只有叶子结点有数据,其它节点不存数据,而且叶子节点之间是相连的。

这样我们就知道为什么索引结构要选B+树了: 

1、B+树的非叶子节点(即索引结构中的目录页)不存储数据,就可以在 16KB 的大小内多存储一些数据页,可以使得树更加“矮胖”,页数更少,减少 IO 次数。

2、叶子结点之间互相连接,亦可以便于范围查找。

2、常见的索引种类

通过前面的介绍我们可以知道,索引实际上是根据我们所取关键字的种类,来构建不同的B+树索引结构的:

2.1  主键索引

以主键为关键字建立的索引,就是主键索引。创建主键索引有三种方式:

-- 1、在创建表的时候,如果指明了主键,就会自动创建主键索引
create table test (id int primary key, age int not null);-- 2、在创建表的最后,指明某列为主键,自动创建主键索引
create table test (id int, age int not null, primary key(id));-- 3、在创建表之后,后添加主键
create table test (id int, age int not null);
alter table test add primary key(id);

可以发现,只要表有了主键,MySQL就会自动帮我们创建主键索引,创建主键索引的三种方式其实也就是添加主键的三种方式。

主键索引的特点:

1、因为一个表中只能有一个主键,所以最多也只能有一个主键索引;当然也可以使用复合索引(即以多个列作为关键字的普通索引,需要多个列全部满足,B+树才往下走)

2、因为主键不能重复,所以主键索引效率比较高。

3、主键索引的列通常都是 int 类型。

4、创建主键索引的列,不能为空,数据也不能重复(就是主键的性质) 

2.2  唯一索引

添加唯一键的时候,MySQL也是会自动帮我们创建唯一索引:

-- 1、在创建表时,直接指明唯一键
create table test2(id int, name varchar(30) unique);-- 2、在创建表的最后,指明一列或多列为唯一键
create table test2(id int, name varchar(30), unique(id), unique(name));-- 3、在创建表之后,后添加唯一键
create table test2(id int, name varchar(30));
alter table test2 add unique(name);

唯一索引的特点:

1、因为唯一键可以有多个,所以一个表中也可以有多个唯一索引。

2、如果以某一列建立唯一索引,这列数据也不能重复(唯一键的性质)

3、查询效率也比较高;如果唯一键指定了不为空,则等价于主键索引。

2.3  普通索引(用的较多)

因为唯一索引和主键索引只要在指明唯一键和主键之后就会自动创建,供用户操作的空间不大,而普通索引列中数据可以重复,还可以取名字,因此普通索引在实际开发中用的比较多:

-- 1、在创建表的最后,指定某列为普通索引
create test3(id int, name varchar(30), index(name));-- 2、在创建完表之后,再指定某列为普通索引
create table test3(id int, name varchar(30));
alter table test3 add index(name);-- 3、直接创建普通索引,普通索引可以起名字
create table test3(id int, name varchar(30));
create index idx_name on test3(name);-- 创建一个名字叫做idx_name的普通索引,关键字是test3表中的name列

普通索引的特点:

1、普通索引可以自己取名字,一个表中也可以有多个普通索引

2、如果某一列需要创建索引,但这一列的数据有重复的,那么就应该创建普通索引。 

2.4  全文索引

当对文字段或有大量文字的字段进行检索时,会使用到全文索引。MySQL提供全文索引机制,但是有要求,要求表的存储引擎必须是MyISAM,而且默认的全文索引支持英文,不支持中文。如果对中文进行全文检索,可以使用sphinx的中文版(coreseek)。

有关全文索引,笔者用的也不多,不再多做赘述。

3、非聚簇索引 VS 聚簇索引

3.1  非聚簇索引:MyISAM存储引擎下与InnoDB 存储引擎非主键索引下的索引方案

3.1.1 MyISAM存储引擎下的非聚簇索引

MyISAM存储引擎的索引方案同样是B+树,只不过其的索引结构中,其叶子结点中只有对应数据和关键字和数据的地址,没有数据,也就是说把数据页和数据目录进行了分离,不放在同一个页中了

非聚簇索引的B+树结构

像这种索引结构B+树的叶子结点里面没有数据,把具体数据和B+树中的数据页进行了分离的索引结构,叫做非聚簇索引。

在MyISAM存储引擎中,是把数据关键字、地址和具体数据进行分离。

3.1.2  InnoDB存储引擎下的非主键索引

InnoDB存储引擎下的非主键索引,采用的索引结构也是非聚簇索引结构,但是其叶子结点存有的是数据关键字和这个数据的主键键值,又称作辅助索引。

辅助索引的存在是为了节省空间,存放更多的目录项;但是其查询就需要两次先通过主键找到主键索引,再通过主键索引找到具体的数据地址,这种查找方式叫做回表查询。 

3.2  聚簇索引:InnoDB存储引擎下的主键索引方案

与非聚簇索引相反,聚簇索引就是B+树索引结构的叶子结点里面既存有数据的关键字、地址,又存有具体的数据,即前文所展示的,一个数据页中,既有目录,又有具体数据;查找都是在一个页里面进行。

4、索引的操作

4.1  索引的创建原则

各类索引如何创建,我们已经在索引种类小结中都介绍了,这里介绍一下在创建普通索引的时候,哪些列适合被创建普通索引,哪些列不适合:
1、频繁被作为查询条件的列,应该创建索引,提高查询效率。

2、但是如果这个列唯一性太差,即便频繁作为查询条件,也不应该被单独作为关键字设置索引,而是应该设置联合索引,提高其唯一性(唯一性太差,关键字重合的可能性就较高,容易进入想查询的数据页并不在的数据页查询,降低效率,对吗)

3、更新过于频繁的列也不适合建立索引,因为如果列发生更新,其建立的索引结构也要发生更新,维护成本高。

4、极少出现在  where 字句中的字段(即极少作为查询条件的字段),不应该设置索引。

5、总结一下,就是唯一性较好、低频被修改、高频做为查询条件的列,适合充当索引关键字,建立索引。

4.2  查看表中的索引信息

-- 1、show index / keys from 表名; 
-- 二者查询结果是一样的
show index from test3;
show keys from test3;-- 2、desc 表名;
-- 这种查询结果比较简略隐晦,一般很少使用
desc test3;
查询示例

4.3  删除索引

-- 1、删除主键索引(必须用这种方法)(其实就是删除主键,主键删除了,主键索引随之删除)
alter table test1 drop primary key;-- 2、其它索引类型的删除
-- 这里有两种方案,结果是一样的
-- 2.1 alter table 表名 drop index 索引名(即show index from 表名 中的 Key_name字段)
alter table test2 drop index unique;
-- 2.2 drop index 索引名 on 表名
drop index idx_name on test3;

5、组合索引(复合索引、联合索引)

索引结构中的关键字由多个列组成,这样的索引叫做组合索引,组合索引支持局部搜索,也就是说可以提供部分关键字来进行查询。

5.1  组合索引最左匹配原则

所谓组合索引最左匹配原则,就是说在局部查询的时候,在进行局部查询时,必须从组合索引的最左边的列开始,并按照索引中列的顺序进行组合。如果查询条件没有从最左边的列开始,或者跳过了中间的列,组合索引将失效。

 (eg:假设在id、name、age字段上已经成功建立了一个名为MultiIdx的组合索引。索引行中按id、name、age的顺序存放,索引可以搜索id、(id,name)、(id, name, age)字段组合。如果列不构成索引最左面的前缀,那么MySQL不能使用局部索引,如(age)或者(name,age)组合则不能使用该索引查询。

5.2  索引覆盖

使用组合索引的时候,如果从索引中找到了某一列,不会再进行回表查询,而是直接把索引的值返回。

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

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

相关文章

【软件工程】一篇入门UML建模图(类图)

🌈 个人主页:十二月的猫-CSDN博客 🔥 系列专栏: 🏀软件开发必练内功_十二月的猫的博客-CSDN博客 💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前…

vue2+ element ui 集成pdfjs-dist

目录 1. 下载Pdf.js1.1 下载1.2 修改配置1.2.1 将pdfjs-3.8.162-dist复制到项目中1.2.2 解决跨域问题1.2.3 将pdf.worker.js文件复制到public目录下1.2.4 安装 pdfjs-dist1.2.5 前端vue代码(示例) 3. 参考资料 1. 下载Pdf.js 1.1 下载 下载链接(官方)需…

蓝桥杯每日真题 - 第7天

题目:(爬山) 题目描述(X届 C&C B组X题) 解题思路: 前缀和构造:为了高效地计算子数组的和,我们可以先构造前缀和数组 a,其中 a[i] 表示从第 1 个元素到第 i 个元素的…

大语言模型:解锁自然语言处理的无限可能

0.引言 在当今的科技时代,自然语言处理技术正以前所未有的速度发展,语言大模型作为其中的核心力量,对各个领域产生了深远的影响。本文旨在探讨语言大模型的发展历程、核心技术以及广泛的应用场景,以帮助读者更好地理解这一前沿技…

【vue2.0入门】vue基本语法

目录 引言一、页面动态插值1. 一般用法 二、计算属性computed三、动态class、style绑定四、条件渲染与列表渲染五、事件处理六、表单输入绑定七、总结 引言 本系列教程旨在帮助一些零基础的玩家快速上手前端开发。基于我自学的经验会删减部分使用频率不高的内容,并不…

【STM32F1】——无线收发模块RF200与串口通信

【STM32F1】——无线收发模块RF200与串口通信 一、简介 本篇主要对调试无线收发模块RF200的过程进行总结,实现了以下功能。 串口普通收发:使用STM32F103C8T6的USART2串口接收中断,实现两个无线收发模块RF200间的通信。 二、RF200介绍 电压…

《TCP/IP网络编程》学习笔记 | Chapter 8:域名及网络地址

《TCP/IP网络编程》学习笔记 | Chapter 8:域名及网络地址 《TCP/IP网络编程》学习笔记 | Chapter 8:域名及网络地址域名系统什么是域名?DNS 服务器IP 地址和域名之间的转换使用域名的必要性利用域名获取 IP 地址利用 IP 地址获取域名 基于 Wi…

前端开发中常用的包管理器(npm、yarn、pnpm、bower、parcel)

文章目录 1. npm (Node Package Manager)2. Yarn (Yarn Package Manager)3. pnpm4. Bower5. Parcel总结 前端开发中常用的包管理器主要有以下几个: 1. npm (Node Package Manager) 简介: npm 是 Node.js 的默认包管理器,也是最广泛使用的包…

HarmonyOS 如何实现传输中的数据加密

文章目录 摘要引言数据传输加密概述选择加密算法和传输协议加密实现方案与 Demo 代码配置 HTTPS/TLSAES 加密的实现代码详解RSA加密的实现代码详解 QA环节总结参考资料 摘要 本文将介绍在 HarmonyOS 应用中如何实现数据传输的加密策略。我们将讨论常见的加密算法(如…

ArkTs简单入门案例:简单的图片切换应用界面

在鸿蒙 OS 应用开发的过程中,我们常常需要通过组合各种组件和编写相应的逻辑来实现丰富多样的功能。今天,我就来和大家详细解析一段实现简单图片切换功能的代码,希望能帮助到那些刚接触鸿蒙 OS 应用开发的朋友们。 一、代码导入部分 Entry …

influxDB 时序数据库安装 flux语法 restful接口 nodjsAPI

安装 Install InfluxDB | InfluxDB OSS v2 Documentation Debian和Ubuntu用户可以用apt-get包管理来安装最新版本的InfluxDB。 对于Ubuntu用户,可以用下面的命令添加InfluxDB的仓库,添加之后即可apt-get 安装influxdb2 wget -q https://repos.influx…

丹摩征文活动|丹摩智算平台使用指南

目录 1. 登录平台与工作环境设置1.1 访问与登录1.2 创建或选择项目1.3 初始化项目环境 2. 数据上传与管理2.1 数据上传2.2 数据管理与预处理2.3 数据可视化 3. 模型构建与训练3.1 模型选择3.2 参数配置3.3 模型训练与评估 4. 模型部署与应用4.1 模型部署4.2 接口调用与集成4.3 …

NAT网络工作原理和NAT类型

NAT基本工作流程 通常情况下,某个局域网中,只有路由器的ip是公网的,局域网中的设备都是内网ip,内网ip不具备直接与外部应用通信的能力。 处于内网的设备如何借助NAT来实现访问外网的应用? 对于开启了NAT功能的局域网…

LLMs 如何处理相互矛盾的指令?指令遵循优先级实验

编者按:想象一下,你正在开发一个 AI 助手,突然发现 system message 和用户提示词存在冲突,这时 AI 会听谁的?这种情况不仅困扰着开发者,还可能导致 AI 系统的不稳定和不可预测,影响用户体验和系…

qt QProcess详解

1、概述 QProcess是Qt框架提供的一个类,它用于在应用程序中执行外部进程。QProcess提供了一系列函数来启动、控制和与外部进程进行交互,使得开发者能够在自己的应用程序中集成和调用其他程序或服务。这个类在需要执行系统命令、启动其他应用程序或进行文…

Appium配置2024.11.12

百度得知:谷歌从安卓9之后不再提供真机layout inspector查看,仅用于支持ide编写的app调试用 所以最新版android studio的android sdk目录下已经没有了布局查看工具... windows x64操作系统 小米k30 pro手机 安卓手机 Android 12 第一步&#xff1a…

《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明

参考 《element plus 使用 icon 图标(两种方式)》使用 icon 升级 Vue2 升级 Vue3 项目时,遇到命名时的实心与空心点差异! ElementUI: 实心是 el-icon-more空心是 el-icon-more-outline ElementPlus: 实心是 el-icon-more-fill…

WebSocket和HTTP协议的性能比较与选择

WebSocket和HTTP协议的性能比较与选择 引言: 在web应用开发中,无论是实时聊天应用、多人在线游戏还是实时数据传输,网络连接的稳定性和传输效率都是关键要素之一。目前,WebSocket和HTTP是两种常用的网络传输协议,它们…

【数据结构与算法】第11课—数据结构之选择排序和交换排序

文章目录 1. 选择排序1.1 直接选择排序1.2 堆排序 2. 交换排序2.1 冒泡排序2.2 快速排序(找基准值法1----Hoare版本)2.2.1 特殊场景12.2.2 特殊场景22.2.3 代码2.2.4 快速排序的时间复杂度 2.3 快速排序(找基准值法2---挖坑法)2.3.1 特殊情况1处理2.3.2 特殊情况2处理 2.4 快速…

MySQL技巧之跨服务器数据查询:进阶篇-从A数据库复制到B数据库的表中

MySQL技巧之跨服务器数据查询:进阶篇-从A数据库复制到B数据库的表中 基础篇已经描述:借用微软的SQL Server ODBC 即可实现MySQL跨服务器间的数据查询。 而且还介绍了如何获得一个在MS SQL Server 可以连接指定实例的MySQL数据库的连接名: MY_ODBC_MYSQ…