MySQL索引(二)

MySQL索引(二)

文章目录

  • MySQL索引(二)
    • MySQL有哪些索引?
      • MySQL的主键是聚簇索引吗?
        • 聚簇索引和非聚簇索引的区别
        • 什么是覆盖索引
        • 什么是回表
        • 主键问题
      • 外键约束
        • 什么是外键
        • 什么是外键约束
        • 外键带来的问题
      • 联合索引
        • 最左匹配原则
        • 如何建立联合索引
        • 索引下推

学习地址:https://xiaolincoding.com/

MySQL有哪些索引?

  • 主键索引(聚簇索引):建立在主键字段上的索引,通常在创建表的时候一起创建,一张表最多一个主键索引,不允许有空值
  • 唯一索引:建立在UNIQUE字段上的索引,一张表可以有多个唯一索引,索引列的值必须唯一,但允许有空值
  • 普通索引:建立在普通字段上的索引,既不要求字段为主键,也不要求字段为UNIQUE
  • 前缀索引:针对字符类型字段的前几个字符建立的索引,前缀索引可以建立在字段类型为char、varchar、binary、varbinary的列上。使用前缀索引是为了减少索引占用的存储空间,提高查询效率
  • 联合索引:通过将多个字段组合成一个索引,这个索引就是联合索引

InnoDB引擎要求每个表都有一个主键索引,比如表中的id字段;查询较为频繁的字段,可以考虑对这个字段建立普通索引,如果是多个字段,考虑建立联合索引;对于长文本、字符串等类型的字段,比如文章标题、商品名称等,我们可以针对这些字段的前缀部分建立前缀索引,这样可以减少索引的存储空间。

MySQL的主键是聚簇索引吗?

聚簇索引就是安装每张表的主键构造一棵B+树,该树的叶子节点存放的是整张表的行记录数据,就是好像把数据和索引聚集在了一棵B+树上,所以这种数据组织形式的索引叫聚簇索引。

InnoDB在创建聚簇索引时,会根据不同情况选择不同的列作为索引:

1.如果定义了主键,默认选择主键

2.如果没有主键,选择第一个不包含NULL的唯一列作为聚簇索引的索引键

3.上面两个条件都不满足,InnoDB自动生成一个隐式自增id(row_id)作为聚簇索引的索引键

聚簇索引和非聚簇索引的区别

聚簇索引和非聚簇索引最主要的区别是:B+树叶子节点存放的内容不同

  • 聚簇索引:主键值+完整记录
  • 非聚簇索引:索引值+主键值

如果查询语句中的查询条件使用了二级索引(非聚簇索引),但是查询的数据不是主键值,也不是二级索引,这时二级索引找到主键值后,就需要回表才能查到数据,需要扫描两次B+树;如果查询的数据是主键值,这时候就会用到覆盖索引,不需要回表,只需要扫描一次B+树。

什么是覆盖索引

二级索引的叶子节点存放的是索引+主键id,如果查询的列能够在二级索引中全部查到,那就不需要去主键索引去查行记录了,这个不需要回表的过程,就叫覆盖索引,效率比较高。

比如有联合索引(a,b),发生以下查询时,就会发生覆盖索引:

  • select a,b,id from table where a=? and b=?
  • select a,b from table where a=? and b=?
  • select b,id from table where a=? and b=?
  • select a,id from table where a=? and b=?
  • select a from table where a=? and b=?
  • select b from table where a=? and b=?
  • select id from table where a=? and b=?

使用explain命令,看extra信息显示了using idex,就代表查询用到了覆盖索引,不涉及回表

image-20240827182941747

什么是回表

在使用二级索引进行查询的时候,如果查询的列,不能在二级索引中全部查询到,那么就需要回到主键索引去查完整的行记录了,这种二级索引通过主键索引进行再一次查询的操作叫做回表

主键问题
  • 主键为什么不能附带业务含义?

1.如果哪个业务字段因为业务需求而有重复,或者重用的情况,等需要变动时再去修改主键成本会很高,不如规避有业务含义的主键

2.业务含义的主键不是自增就会产生页分裂问题,从而影响性能

  • 主键使用自增还是UUID?

使用自增比较好,因为UUID是随机值,在数据插入时,会导致索引树发生页分裂的问题,从而影响性能,而且UUID是字符串类型,长度也比较长,占用内存比较大,而页的大小是固定的,这会导致索引树的高度越高,查询时发生的磁盘IO变多,性能就更低

但是在自增id在分库分表环境下就不适用了,因为没办法全局唯一,这时候就得考虑使用雪花算法作为主键了。

  • 什么是页分裂问题?

如果我们使用非自增主键,每次插入主键的索引值都是随机的,因此每次插入新的数据时,可能就会插入到现有的某个页中间的位置,这下就不得不移动其他数据来满足新数据的插入,甚至需要从一个页面复制数据到另一个页面,我们通常把这种情况称为页分裂。

页分裂会导致大量的内存碎片,导致索引结构不紧凑,从而影响查询效率。

举例:假设某个数据页中的数据是1、3、5、9,而且数据页满了,现在需要插入一个数据7,则需要把数据页分为两个数据页:

image-20240827202039079

出现页分裂时,需要把一个页的记录移动到另一个页,性能受到影响,同时页空间的利用率下降,造成存储空间的浪费。

ps:页内记录其实是单链表存储,并不是连续存储。

B+树的数据都是有序的1,所以:

1.如果我们使用的主键是顺序递增,那么每次插入的新数据就会顺序插入到叶子节点最右边的节点里,如果该页面满了就会去开辟一个新页面,将新数据插入到新页面中。因为每次插入新纪录都是追加操作,不需要移动数据,所以效率很高

2.如果我们使用的主键不是顺序递增,由于每次插入主键的索引值都是随机的,因此每次插入新数据时就可能插入到数据页中间的某个位置,这时候为了保证B+树的有序性,要移动其他数据来满足新数据的插入。如果页面满了,就会发生页分裂,这时候就要从一个页面复制数据到另一个页面,目的是保证后一个数据页中的所有主键比前一个数据页中的主键值大,页分裂可能会造成大量内存碎片,导致索引结构不紧凑,从而影响查询效率。

所以,我们在设计主键时,最好采用自增的方式,或者顺序递增主键值。

  • 主键怎么设置

1.创建表时,把id列设置为PRIMARY KEY,那这个id列就是主键索引了。

CREATE TABLE table_name (id INT PRIMARY KEY,column1 datatype,column2 datatype,...
);

2.如果没有主键,选择第一个不包含NULL的唯一列作为聚簇索引的索引键

3.上面两个条件都不满足,InnoDB自动生成一个隐式自增id(row_id)作为聚簇索引的索引键

外键约束

什么是外键

两张表,表A、表B,它们通过一个公共字段id发生关联关系,这个关系叫R。

如果这个id在表A里是主键,那么表A就是这个关系R中的主表,表B就是从表。表B中的id就是表B来引用表A的数据的,所以叫外键。

外键就是从表用来引用主表中数据的公共字段。

image-20240827203645382

什么是外键约束

外键约束保证了数据引用的完整性,也就是从表的外键必须存在于主表的主键中,如果发现删除的主表记录,正在被从表的某条记录的外键字段所引用,那么就会报错不允许删除,保证了两张表的一致性。

  • 数据的一致性:如果一个订单表引用了客户表的外键,外键可以保证订单的客户ID存在客户表中,保证数据的一致性

  • 数据的完整性:外键可以防止在引用表中删除正在被其他表引用的记录,保证数据的完整性

但是一般公司都明确不使用外键约束,如果数据存在外键关系,请在程序层面实现。

外键带来的问题
  • 性能问题

有了外键,每次增删改都需要额外检查外键约束,会占用数据库的计算资源,影响增删改的性能

  • 锁问题

有了外键,每次修改数据都要去检查外键关联表中的数据,这需要额外获取读锁在高并发场景下很容易发生死锁问题

  • 分库分表

外键难以跨越不同数据库来建立关系,所以在分布式、高并发集群的项目中一般不使用外键。

联合索引

最左匹配原则

如果创建了一个(a,b,c)的联合索引,联合索引的索引顺序是这样的,是先按a排序,在a相同的情况下再按b排序,在b相同的情况再按c排序。

因此在使用联合索引时,存在最左匹配原则。

例如,一个(a,b,c)的联合索引,查询条件为WHERE a=1 AND b=2时,MySQL可以使用这个索引进行查询,因为查询条件匹配了索引的最左边的两个列;如果查询条件为WHERE b=2 AND c=3时,则MySQL无法使用这个索引进行查询,因为查询条件不匹配索引的最左边的列。

  • MySQL会从联合索引最左边的索引开始匹配查询条件,然后依次按从左到右的顺序匹配,如果查询条件没有使用到某个列,那么该列右边的所有列都无法使用索引
  • 当查询条件中使用了某个列,但是该列的值包含范围查询,范围查询的字段可以使用到联合索引,但是在范围查询字段的后面的字段无法用到联合索引

所以我们在使用联合索引时,需要遵守最左匹配原则,否则会出现部分索引字段走不了索引的情况。

如何建立联合索引

建立联合索引时的字段顺序,对索引效率也有很大影响。越靠前的字段被用于索引过滤的概率就越高,实际开发中建立联合索引时,要把区分度大的字段排在前面,这样区分度大的字段越有可能被更多的SQL使用到

比如,性别区分度很小,不适合做索引或排在联合索引靠前的位置;UUID就很适合做索引或排在联合索引靠前的位置。

如果索引的区分度很小,假设字段值分布均匀,那么无论搜索哪个值都可能得到得到一半的数据。在这些情况下,不如不走索引。所以MySQL有一个查询优化器,查询优化器发现某个值出现在表中的数据行的百分比很高时(一般是30%),它一般会拒绝走索引,进行全表扫描

索引下推

索引下推能够减少二级索引在查询时的回表操作,提升查询的效率,因为它把Server层负责的事情,交给了存储引擎层做处理。

举例:

联合索引,(name,age)

nameagescore
张三10100
李四2080
王五3040
张六1310

查询语句:

select * from user where name like `张%` and age=10;

如果按照最左匹配原则,联合索引遇到范围查询时就会停止匹配,也就是只有name字段可以用到联合索引,但是age字段无法利用索引。

  • 如果不使用索引下推:

操作1:Server层先定位到满足查询条件的第一个二级索引记录,也就是定位到张%的第一条记录,张三。

操作2:存储引擎根据二级索引的B+树快速定位到记录后,获取主键值,然后回表操作,将完整记录返回给Server层。

操作3:Server层判断该记录的age是否等于10,如果成立,返回给客户端;如果不成立,跳过该记录。

操作4:接着继续向存储引擎索要下一条记录,根据二级索引的B+树快速定位到记录后,获取主键值,然后回表操作,将完整记录返回给Server层(重复操作2)。

如此重复,直到把存储引擎中的所有记录读完。

我们可以看到,没有索引下推时,每查询到一条二级索引记录,都需要进行回表操作,然后把记录返回给Server,接着Server再判断该记录的条件是否满足(age是不是等于10)。

使用索引下推后,就把Server层判断age是不是等于10交给了存储引擎层:

操作1:Server层先定位到满足查询条件的第一个二级索引记录,也就是定位到张%的第一条记录,张三。

操作2:存储引擎定位到二级索引后,先不执行回表操作,而是判断一下该索引是否包含列的条件(age列)是否成立(age是不是等于10)。如果不成立,跳过该二级索引;如果成立,执行回表操作,把完整记录返回给Server层。

操作3:Server层判断其他的查询条件(示例中没有写其他条件)是否成立,成立则发生给客户端;否则跳过该记录,向存储引擎索要下一条记录。

如此重复,直到把存储引擎中的所有记录读完。

我们可以看到,使用索引下推后,虽然age列不能使用联合索引,但是它包含在联合索引中,所以直接在存储引擎中过滤满足age=10的条件后,才去回表获取整个记录,省去了很多回表操作。

当extra=Using index condition,说明使用了索引下推。

使用explain查询到,extra=Using index condition表明了使用了索引下推。

image-20240827221039081

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

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

相关文章

Kubernetes设计架构

目录 1. 集群(Cluster) 2. 主节点(Master Node) 3. 工作节点(Worker Node) 4. Pod 5. 服务(Service) 6. 命名空间(Namespace) 7. 配置管理 8. 持久化…

Android Auto推出全新Google助手设计

智能手机与汽车的无缝整合已成为现代驾驶的重要组成部分,而 Android Auto 一直在这一领域处于领先地位。谷歌通过不断推出新功能和更新,体现了其致力于提升 Android Auto 体验的决心。最近,Android Auto 引入了 Google助手的全新设计。 当系…

微信小程序代码目录结构介绍

文件描述app.js小程序的入口文件,负责监听和处理小程序的生命周期函数,以及定义一些全局的公共方法和数据。app.json公共全局配置文件。app.wxss公共全局样式文件。project.config.json项目的配置文件,包含一些项目级别的配置,如项…

科研绘图系列:R语言对角线矩阵图(corrplot plot)

介绍 对角线矩阵图(Diagonal Matrix Plot)是一种特殊类型的图表,用于可视化对角线矩阵中的元素。对角线矩阵是一种方阵,其中非对角线上的元素都是零,而对角线上的元素可以是任意值。这种矩阵在数学和计算机科学中非常有用,尤其是在线性代数、特征值问题和对角化等操作中…

使用 OpenCV 组合和缩放多张图像

在图像处理领域,我们经常需要将多张小图像组合成一张大图。例如,将多张图像按一定布局排列在一起,或者创建一个缩略图画廊。在这篇博客中,我将向你展示如何使用 Python 的 OpenCV 库来完成这一任务。 代码 下面是一段完整的 Pyt…

IO进程线程8月27日

1&#xff0c;思维导图 2&#xff0c;使用两个线程分别复制文件的上下两部分到同一个文件 #include<myhead.h> sem_t fastsem; //pthread_mutex_t fastmutex; void *capy_up(void *c) { // pthread_mutex_lock(&fastmutex);int len*(int *)c;int fp1open("./1…

代码随想录 刷题记录-18 动态规划(2)01背包问题、习题

一、01背包理论基础 例题&#xff1a;46. 携带研究材料 01 背包 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 暴力解法&#xff1a…

SparkShop开源商城 uploadFile 任意文件上传漏洞复现

0x01 产品简介 SparkShop开源商城(也被称为星火商城)是一款基于ThinkPHP6和Element UI的开源免费可商用的高性能商城系统。适用于各类电商场景,包括但不限于B2C商城、新零售、分销商城等。无论是初创企业还是成熟品牌,都可以通过SparkShop快速搭建个性化独立商城,实现线上…

PHPShort轻量级网址缩短程序源码开心版,内含汉化包

需要网址缩短并且想获得更多有关链接点击率和流量的数据分析&#xff0c;那么 PHPShort 可能是一个非常好的选择。PHPShort 是一款高级的 URL 缩短器平台&#xff0c;可以帮助你轻松地缩短链接&#xff0c;并根据受众群体的位置或平台来定位受众。 该程序基于 Laravel 框架编写…

【Python机器学习】NLP分词——利用分词器构建词汇表(一)

在NLP中&#xff0c;分词&#xff08;也称切词&#xff09;是一种特殊的文档切分过程。而文档切分能够将文本切分成更小的文本块或片段&#xff0c;其中含有更集中的信息内容。文档切分可以是将文本分成段落&#xff0c;将段落分成句子&#xff0c;将句子分成短语&#xff0c;或…

GUI编程03:3种布局管理器

本节内容视频链接&#xff1a;https://www.bilibili.com/video/BV1DJ411B75F?p5&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5https://www.bilibili.com/video/BV1DJ411B75F?p5&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 1.FlowLayout 流式布局 代码&#xff1a;…

c++类的继承

1.直接继承父类的方法 #include <iostream> #include <string>using namespace std; class Person{ public:void eat(){cout<<"在吃饭"<<endl;} }; class Student : public Person{ private:int age; public:string name;Student() {cout &…

echarts倾斜横向堆叠柱状图

代码如下 option: {backgroundColor: "transparent",tooltip: {trigger: "axis",axisPointer: {lineStyle: {color: {type: "linear",x: 0,y: 0,x2: 0,y2: 1,colorStops: [{offset: 0,color: "rgba(126,199,255,0)", // 0% 处的颜色}…

docker创建数据库容器并映射存储数据

docker创建数据库容器并映射存储数据 介绍创建Redis容器创建PostgresQL容器创建MySQL容器 介绍 使用Docker创建Redis、PostgresQL、MySQL等数据库容器代码示例。 创建Redis容器 使用Docker创建Redis容器并使用Volume映射存储数据是一个常见的操作。以下是详细的步骤&#xf…

云计算环境下的等保测评要点分析

在云计算环境下进行等保测评时&#xff0c;需要关注以下几个关键点&#xff1a; 安全责任共担模型&#xff1a;明确云服务提供商&#xff08;CSP&#xff09;与云服务用户&#xff08;CSU&#xff09;之间的安全责任划分&#xff0c;确保双方在安全防护上的协同作用。 安全控制…

Web开发:通过Quatz开启定时任务调度的基础demo

一、demo程序 【需求】实现每10分钟输出当前时间到txt文档 using Quartz; using Quartz.Impl; using System; using System.IO; using System.Threading.Tasks;namespace QuartzDemo {class Program{static async Task Main(string[] args){// 创建一个调度程序实例ISchedule…

nacos的配置更改了还要重启服务才生效

optoelectronic:azimuth: 117.1pitch: -3.81distance: 0.25 原写法: import lombok.Data; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component;import javax.annotation.PostConstruct; import java.math.BigDecima…

J.U.C Review - 基本概念:进程、线程、线程组、优先级

文章目录 进程与线程的故事1.1 进程的诞生对操作系统的要求进一步提高为什么我们要使用多线程&#xff1f; 1.2 上下文切换的故事 Java多线程入门1. 继承Thread类代码示例 2. 实现Runnable接口代码示例 3. Thread类的构造方法和常用方法构造方法常用方法 4. Thread类与Runnable…

数据结构(邓俊辉)学习笔记】串 07——KMP算法:分摊分析

文章目录 1.失之粗糙2.精准估计 1.失之粗糙 以下&#xff0c;就来对 KMP 算法的性能做一分析。我们知道 KMP 算法的计算过程可以根据对齐位置相应的分为若干个阶段&#xff0c;然而每一个阶段所对应的计算量是有很大区别的。很快就会看到&#xff0c;如果只是简单地从最坏的角…

Qt5.14.2 操作PostgreSQL 记录

在Qt5.14.2中操作PostgreSQL数据库. #include <QSqlDatabase> #include <QSqlQuery> #include <QSqlError> #include <QDebug>// 初始化数据库连接QSqlDatabase db QSqlDatabase::addDatabase("QPSQL");//qDebug() << "aaaa&qu…