MySQL索引特性(下)

news2024/11/14 21:51:24

目录

索引的理解

理解单个Page

 理解多个Page

 页目录

 单页情况

 多页情况

  复盘一下

 聚簇索引VS非聚簇索引

区别

 索引操作

主键索引

 唯一索引的创建

 普通索引的创建

查询索引 

 删除索引

索引创建原则 

索引的理解

理解单个Page

MySQL 中要管理很多数据表文件,而要管理好这些文件,就需要先描述,在组织 ,我们目前可以简单理解 成一个个独立文件是有一个或者多个Page构成的。

不同的 Page ,在 MySQL中,都是16KB,使用 prev 和 next 构成双向链表;
因为有主键的问题,MySQL 会默认按照主键给我们的数据进行排序
,从上面的Page内数据记录可以看出,数据是有序且彼此关联的;
这个排序是MySQL自己做的

为什么数据库在插入数据时要对其进行排序呢?我们按正常顺序插入数据不是也挺好的吗? 插入数据时排序的目的,就是优化查询的效率。 页内部存放数据的模块,实质上也是一个链表的结构,链表的特点也就是增删快,查询修改慢,所以优化查询的效率是必须的。 正式因为有序,在查找的时候,从头到后都是有效查找,没有任何一个查找是浪费的,而且,如果运气好,是可以提前结束查找过程的

如果没有主键则插入什么顺序查找就是什么顺序

 理解多个Page

通过上面的分析,我们知道,上面页模式中,只有一个功能,就是在查询某条数据的时候直接将一整页的数据加载到内存中,以减少硬盘IO次数,从而提高性能。但是我们也可以看到,现在的页模式内部,实际上是采用了链表的结构,前一条数据指向后一条数据,本质上还是通过数据的逐条比较来取出特定的数据。

如果有1千万条数据,一定需要多个Page来保存1千万条数据,多个Page彼此使用双链表链接起来,而且每个Page内部的数据也是基于链表的。那么查找特定一条记录,也一定是线性查找,这效率也太低了。 

 

 页目录

我们在看《三国演义》这本书的时候,如果我们要看武松那一章节,找到该章节有两种做法:
1. 从头逐页的向后翻,直到找到目标内容

2. 通过书提供的目录,发现指针章节在234页(假设),那么我们便直接翻到234页。同时,查找目录的方案,可以顺序找,不过因为目录肯定少,所以可以快速提高定位

本质上,书中的目录,是多花了纸张的,但是却提高了效率,所以,目录,是一种“空间换时间的做法”

 单页情况

针对上面的单页Page,我们也当然可以引入目录;


page牺牲一部分空间用来存目录(目录不会很大),目录只有两个字段:第一个就是指向它起始记录的key值;第二个是有一个指针字段,指向记录的起始位置;

在一个Page内部,我们引入了目录。比如,我们要查找id=4记录,之前必须在数据记录里线性遍历4次, 才能拿到结果。现在直接通过目录2[3],直接进行定位新的起始位置,再通过指针找到这条记录,再往下遍历从而提高了效率(查找次数变少了)。我们不用直接在数据记录里查找了而是先在目录里找再在数据记录里找;

所以只有数据有序了才能方便引入页内目录;就相当于一本书也是有序的,才能有目录;

 多页情况

MySQL 中每一页的大小只有 16KB ,单个Page大小固定,所以随着数据量不断增大, 16KB不可能存下所有的数据,那么必定会有多个页来存储数据。

 在单表数据不断被插入的情况下, MySQL 会在容量不足的时候,自动开辟新的Page来保存新的数据,然后通过指针的方式,将所有的Page组织起来。page之间是线性连接的,

需要注意上面的图是理想结构,大家也知道,目前要保证整体有序,那么新插入的数据,不一定会在新Page上面,这里仅仅做演示。

这样,我们就可以通过多个Page遍历,Page内部通过目录来快速定位数据。可是,貌似这样也有效率问题,在Page之间,也是需要 MySQL 遍历的(线性连接),遍历意味着依旧需要进行大量的IO(比如我要找的数据在结尾,那么我就要遍历所有page太费时),将下一个Page加载到内存,进行线性检测(在内存中才能遍历,遍历本身就是线性检测,效率低下)。这样就显得我们之前的Page内部的目录,有点杯水车薪了。

那么如何解决呢?解决方案,其实就是我们之前的思路,给Page也带上目录

1. 使用一个目录项来指向某一页,而这个目录项存放的就是将要指向的页中存放的最小数据的键值。(再创page存目录,这个page不存数据只存目录)

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

3. 其中,每个目录项的构成是:键值+指针。图中没有画全。
存在一个目录页来管理页目录,目录页中的数据存放的就是指向的那一页中最小的数据(既最小主键值)有数据,就可通过比较并且找到该访问那个Page,进而通过指针,找到这个Page。

其实目录页的本质也是页,普通页中存的数据是用户数据,而目录页中存的数据是普通页的地址。

那么当子page存储的数据多了,上级目录也便多了,那么从宏观上来讲是不是也是遍历查找,那么我们可以再在上级目录加目录,可以在加目录页: 这就是传说中的B+树(多叉树)啊!没错,至此,我们已经给我们的表构建完了主键索引。 随便找一个id=x我们发现,现在查找的Page数一定减少了,也就意味着IO次数减少了,那么效率也就提高了。
所以不是所有的索引都是用B+树存储的,但是主流是B+树不论哪个存储引擎都是;只有最底层的page之间用指针前后互连,上层的都不用;

叶子节点保存真实表中的数据,路上节点(沿途的节点)不保存数据,非叶子节点不要数据只要目录项,意味着可以存储更多的目录项,那么目录页可以管理更多的叶子page,那么这棵树就一定是矮胖树(未来搜索都是由根到叶子节点),如果比较矮胖那么途径路上节点变少(每个page都是从磁盘IO来的到内存中)则找到目标数据只需更少的page(减少了IO次数,提高了效率),每一个节点都有目录项可以提高搜索效率;

所以我们把上面的树叫做mysql innode db下的索引结构!一般我们建表插入数据的时候,就是在该结构下CURD,即使自己没有设置主键也是这样的结构,因为mysql会自己设置主键(mysql设置的主键是隐藏列的),所以根据主键搜索快,不是主键搜索慢

叶子节点全部用链表互联起来,那为什么叶子节点是互联呢?首先,这是B+树的特点;其次我们比较希望进行范围查找

  复盘一下

1. Page分为目录页和数据页。目录页只放各个下级Page的最小键值。

2. 查找的时候,自定向下找,只需要加载部分目录页到内存,即可完成算法的整个查找过程,大大减少了IO次数

 InnoDB 在建立索引结构来管理数据的时候,其他数据结构为何不行?

链表?线性遍历

二叉搜索树(二叉搜索树一定是瘦高状的)?退化问题,可能退化成为线性结构

AVL &&红黑树?虽然是平衡或者近似平衡,但是毕竟是二叉结构,相比较多阶B+,意味着树整体 过高,大家都是自顶向下找,层高越低,意味着系统与硬盘更少的IO Page交互。虽然它可以解决问题但是有更优秀的。

Hash?官方的索引实现方式中, MySQL 是支持HASH的,不过 InnoDB 和 MyISAM 并不支持.Hash跟进其算法特征,决定了虽然有时候也很快(O(1)),不过,在面对范围查找就明显不行,另外还有其他差别,有兴趣可以查一下。
 

各种存储引擎

 B树?最值得比较的是 InnoDB 为何不用B树作为底层索引?

B树

B+树 

那么我们了解B+树非叶子节点不存储数据,数据全部都在叶子节点并且叶子节点全部用链式结构连接起来;

B树呢除了叶子节点有数据,其他节点也存储数据并且叶子节点不会互联;

那为什么选择B+树不选B树呢?首先因为MySQL认为如果你在节点里加了数据那么所保存的目录项变少了,那么一个目录页所管理的page变少了那么相对的B树高度会高一点,那么可能需要更多的IO,IO的时间成本比算法的时间成本是更高的;其次B树叶子节点没有整体相连,那么我们进行范围查找的时候需要再次遍历这颗B树则注定了需要每次都要查B树,可能又需要IO因为有的配置可能不在内存中,需要IO到内存中,不像B+树找到起始位置既可线性遍历

总之:B树节点既有数据又有Page指针,而B+只有叶子节点有数据,其他目录页只有键值和 Page指针 ;B+叶子节点全部相连,而B没有;

为何选择B+ :节点不存储data,这样一个节点就可以存储更多的key从而可以使得树更矮,所以IO操作次数更少。 叶子节点相连,更便于进行范围查找;

 聚簇索引VS非聚簇索引

MyISAM存储引擎-主键索引
MyISAM 引擎同样使用B+树作为索引结果,叶节点的data域存放的是数据记录的地址。下图为 MyISAM表的主索引,Col1 为主键。叶子节点本来存数据但是现在存这条记录的地址;

第一列为主键索引

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

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

区别

mysql> create table test1(

id int primary key,

name varchar(20) not null
)engine=innodb;

现在使用的是mysql客户端,访问的是mysqld服务端,把sql交给sql建表;


一张表对应两个文件,frm对应表结构数据,idb该表对应的主键索引和用户数据

 mysql> create table test2(

id int primary key,

name varchar(20) not null

)engine=myisam;



一张表对应三个文件;frm对应表结构数据,MYD该表对应的数据,当前没有数 据,所以是0,MYI该表对应的主键索引数据

 当然, MySQL 除了默认会建立主键索引外,我们用户也有可能建立按照其他列信息建立的索引,一般这种索引可以叫做辅助(普通)索引。
对于 MyISAM ,建立辅助(普通)索引和主键索引没有差别,无非就是主键不能重复,而非主键可重复。

以第二列为键值构建B+树

索引的本质就是数据结构 

同样 InnoDB 除了主键索引,用户也会建立辅助(普通)索引,我们以上表中的 Col3 建立对应的辅助索引如下图:

 可以看到, InnoDB 的非主键索引中叶子节点并没有数据,而只有对应记录的key值。

所以通过辅助(普通)索引,找到目标记录,需要两遍索引:首先检索辅助索引获得主键,然后用主键 到主索引中检索获得记录。这种过程,就叫做回表查询

为何 InnoDB 针对这种辅助(普通)索引的场景,不给叶子节点也附上数据呢?原因就是太浪费空间了,存两份没必要导致回表。

只要有主键必定有索引;如果你构建了主键,那么你的表就会配上主键索引;如果主键建立好,未来你可能会对其他列设定索引的话,可以手动添加,添加后在mysql内部重新构建B+树,只不过innodb对应的是主键值方便我们快速索引,mynisam就会直接指向记录;一张表可能会对应多颗B+树;

 索引操作

索引一般分为:主键,唯一键,普通索引;

主键索引

第一种方式:

在创建表的时候直接在字段名后指定

primary key create table user1(id int primary key, name varchar(30));

  第二种方式:

在创建表的最后,指定某列或某几列为主键索引

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

  第三种方式:

create table user3(id int, name varchar(30));

-- 创建表以后再添加主键

alter table user3 add primary key(id);

主键索引的特点:一个表中,最多有一个主键索引,当然可以使符合主键;主键索引的效率高(主键不可重复);创建主键索引的列,它的值不能为null,且不能重复;主键索引的列基本上是int  

 唯一索引的创建

 第一种方式:

在表定义时,在某列后直接指定unique唯一属性。

create table user4(id int primary key, name varchar(30) unique);

  第二种方式:

创建表时,在表的后面指定某列或某几列为unique

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

  第三种方式:

create table test(id int primary key, name varchar(30));

alter table user1 add unique(name);


两颗B+树,第一个是primary打在id列是btree,第二个是索引名称叫name(以列名为名称),打在name列,类型BTREE        

 唯一索引的特点: 一个表中可以有多个唯一索引;查询效率高 ;如果在某一列建立唯一索引,必须保证这列不能有重复数据 ;如果一个唯一索引上指定not null,等价于主键索引;

 普通索引的创建

第一种方式

mysql> create table test3(

id int primary key,

name varchar(20) not null,

email varchar(30),

index(name)

);在表的定义最后,指定某列为索引

第二种方式

create table user3(id int primary key, name varchar(20), email varchar(30));

alter table user3 add index(name); --创建完表以后指定某列为普通索引
创建多列为索引:mysql> alter table test3 add index(name,email);但还是创建一个B+树,他俩合并才是一个B+树;多列的话默认使用第一个为B+树的名称,我这里因为已经有了名称为name的B+树,所以会显示name_2

它俩共用一个B+树,合起来才是完整的一个

mysql> alter table test3 drop index name_2;发现没有3和4了只有1和2了 

 我们把多列构建起来的索引叫做复合索引。通过复合索引可以避免回表查询,例如我要通过name找email,拿到主键值就返回了

第三种方式

create table user10(id int primary key, name varchar(20), email varchar(30));

-- 创建一个索引名为 idx_name 的索引

create index idx_name on user10(name);

 普通索引的特点: 一个表中可以有多个普通索引,普通索引在实际开发中用的比较多 ;如果某列需要创建索引,但是该列有重复的值,那么我们就应该使用普通索引;

查询索引 

第一种方法: show keys from 表名\G

第二种方法: show index from 表名\G
索引名叫primary,打在id列,索引类型是BTREE(B+)

第三种方法(信息比较简略): desc 表名;

 删除索引

第一种方法-删除主键索引: alter table 表名 drop primary key;

第二种方法-其他索引(除了主键以外的)的删除:

alter table 表名 drop index 索引名; 索引名就是show keys from 表名中的 Key_name 字段

mysql> alter table user10 drop index idx_name;

第三种方法方法: drop index 索引名 on 表名

mysql> drop index name on user8;

索引创建原则 

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

2. 唯一性太差的字段不适合单独创建索引(比如性别就只有男女,B+树构建了也不是好的B+树),即使频繁作为查询条件

3. 更新非常频繁的字段不适合作创建索引(改动太频繁了,索引结构可能变化)

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

 就比如查找员工原来先行检测需要十几秒,加了索引构建B+树它不在建立而是查找索引当然快;

 

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

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

相关文章

阿里云ECS跨区域迁移,利用老操作系统作为新服务操作系统

由于特殊原因或者数据备份需要迁移ecs服务器 1.老服务快照 选择ecs实例,点开实例 进入云盘 https://ecs.console.aliyun.com/disk 在云盘上点击建立快照 2.准备oss同源 购买oss 存储,用于临时备份 https://oss.console.aliyun.com/bucket/ 记得必…

Spring如何进行动态注册Bean

在Spring框架中,Bean是应用程序的核心组成部分,而BeanDefinition则是这些Bean的元数据表示。随着应用程序的复杂性增加,我们可能需要更灵活地定义和注册Bean。Spring框架提供了几个扩展点,允许我们以编程方式影响Bean的创建和定义…

Window中 Redis下载安装

Redis7.2.3连接: 我用夸克网盘分享了「redis-windows-7.2.3.zip」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。 链接:https://pan.quark.cn/s/4dfb0497707a 在安…

Uniapp基础篇(持续更新)

1. Uni-app常用内置组件 view 视图容器 scroll-view 可滚动视图区域,用于区域滚动。需注意在webview渲染的页面中,区域滚动的性能不及页面滚动。 swiper 滑块视图容器。一般用于左右滑动或上下滑动,比如banner轮播图。 image uniapp官方iam…

封装网络请求 鸿蒙APP HarmonyOS ArkTS

一、效果展示 通过在页面直接调用 userLogin(params) 方法,获取登录令牌 二、申请网络权限 访问网络时候首先需要申请网络权限,需要修改 src/main 目录下的 module.json5 文件,加入 requestPermissions 属性,详见官方文档 【声明权…

Flink底层原理解析:案例解析(第37天)

系列文章目录 一、flink架构 二、Flink底层原理解析 三、Flink应用场景解析 四、fink入门案例解析 文章目录 系列文章目录前言一、flink架构1. 作业管理器(JobManager)2. 资源管理器(ResourceManager)3. 任务管理器(Ta…

Hadoop安装报错

报错:ERROR 2023-03-09 21:33:00,178 NetUtil.py:97 - SSLError: Failed to connect. Please check openssl library versions. 解决方案: 在安装失败得客户端执行 编辑 /etc/python/cert-verification.cfg 配置文件,将 [https] 节的 verify 项 设为禁用…

【教学类-67-02】20240716毛毛虫ABB排序

背景需求: 【教学类-67-01】20240715毛毛虫AB排序-CSDN博客文章浏览阅读584次,点赞16次,收藏6次。【教学类-67-01】20240715毛毛虫AB排序https://blog.csdn.net/reasonsummer/article/details/140443310 在AB排序基础上,继续制作…

【JavaEE精炼宝库】 初识网络原理——网络通信基础 | 协议

文章目录 一、网络发展史1.1 独立模式:1.2 网络互连:1.3 局域网(LAN):1.4 广域网(WAN): 二、网络通信基础2.1 IP地址:2.2 端口号: 三、协议3.1 协议的概念&am…

RabbitMQ:基础篇

1.RabbitMQ是高性能的异步通讯组件 何为异步通讯 打电话就是同步通讯,微信聊天可以理解为异步通讯,不是实时的进行通讯:时效性差。 同步调用的缺点: 拓展性差(需求不尽提) 性能下降 级联失败 …

实时高清无延迟:EasyDSS/EasyCVR无人机直播技术重塑赛事新体验

近日有网友发视频称,在内蒙古呼伦贝尔一景区的马术表演现场,一架无人机擅自在场地上空飞行拍摄。现场工作人员多次制止飞行无果,一名表演者骑马用弓箭将无人机射落。 在数字科技日新月异的今天,无人机直播推流技术以其独特的视角…

在GPU上运行PyTorch

文章目录 1、查看GPU的CUDA版本2、下载CUDA版本3、安装cuDNN4、配置CUDA环境变量5、安装配置Anaconda6、使用Anaconda7、pycharm导入虚拟环境8、安装带GPU的PyTorch⭐9、总结 🍃作者介绍:双非本科大三网络工程专业在读,阿里云专家博主&#x…

字节跳动十年经验老鸟,耗时大半年整理的软件测试面试真题【附答案】

软件测试工程师,和开发工程师相比起来,虽然前期可能不会太深,但是涉及的面还是比较广的。前期面试实习生或者一年左右的岗位,问的也主要是一些基础性的问题比较多。涉及的知识主要有MySQL数据库的使用、Linux操作系统的使用、软件…

回溯算法的去重问题

概述 在利用回溯算法去求子集、排列、组合等问题时,所给数组中如果包含重复元素,需要进行去重操作。常用的去重方法是使用used数组或集合。 对于上述子集、排列、组合等问题的求解方法是将数组转化为树的形式,利用递归和回溯的方法进行求解…

10.1 JSP语言入门

JSP语言入门 目录一、 基础概念1. 什么是JSP?2. 工作原理3. 基本语法 二、 表达式语言(EL)1. 简介2. 语法 三、 JSTL(JSP Standard Tag Library)1. 简介2. 核心标签库3. 常用标签 四、 高级话题1. 会话管理2. 自定义标…

卷积神经网络(一)-LeNet-5

前言 LeNet开启了卷积神经网络的第一枪,这一网络模型由Yann LeCun等人在1998年提出,被视为卷积神经网络的开山之作。 论文地址: http://yann.lecun.com/exdb/publis/pdf/lecun-01a.pdf 如果打不开就看csdn: https://download.…

LangChain-v0.2 Build an Agent 构建代理

语言模型本身不能采取行动,它们只是输出文本。LangChain的一个重要用例是创建代理。代理是使用LLM作为推理引擎来确定要采取哪些行动,以及传递哪些输入的系统。执行操作后,可以将结果反馈到LLM中,以确定是否需要更多操作&#xff…

陪玩系统小程序模式APP小程序H5系统搭建开发

随着移动互联网的营及和游戏行业的蓬轨发展,陪玩服务应远而生并迅速唱起,陪玩系统小程序作为连接游戏玩家与陪玩师的桥梁,其模式系统的搭建与开发是得尤为重要,本文将洋细凰述陪玩系统小程宗模式系统的搭建开发流程,包…

基础动态规划题目基础动态规划题目

目录 题目1: P1216 [USACO1.5] [IOI1994]数字三角形 Number Triangles 代码示例: 题目2: Common Subsequence 代码示例 题目3 :最长上升子序列 最长不下降子序列 最长上升子序列oj答案 题目1: P1216 [USACO1.5]…

Linux热键,shell含义及权限介绍

君子忧道不忧贫。 —— 孔丘 Linux操作系统的权限 1、几个常用的热键介绍1、1、[Tab]键1、2、[ctrl]-c1、3、[ctrl]-d1、4、[ctrl]-r 2、shell命令以及运行原理3、权限3、1、什么是权限3、2、权限的本质3、3、Linux中的用户3、4、Linux中文件的权限3、4、1、快速掌握修改权限的…