MySQL索引(二)

news2024/11/14 15:07:26

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

接在存储引擎中过滤满足age=10的条件后,才去回表获取整个记录,省去了很多回表操作。

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

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

[外链图片转存中…(img-Y8MnGVmE-1724769522223)]

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

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

相关文章

适合 Spring Boot 3.0x的Redis 分布式锁

Spring Boot 中的 Redis 分布式锁 在分布式系统中,多个进程同时访问共享资源时,很容易出现并发问题。为了避免这些问题,我们可以使用分布式锁来保证共享资源的独占性。Redis 是一款非常流行的分布式缓存,它也提供了分布式锁的功能…

Ai+若依(页面调整--去除若依的各种痕迹,采用自己的):【07篇】

页面调整 如果使用若依框架项目做为脚手架,那么我们肯定需要在页面显示中,符合自己公司或者项目的标识才行,需要更换的地方很多,我们依次来解决它 浏览器标签页logo标识、标题 系统页面中的logo标识、标题 去除源码地址 & 文档地址 主题风格和菜单图标 登录名称及背景…

Java GIS开发工具包-GeoTools浅谈

目录 前言 一、关于Geotools 1、GeoTools简介 2、官方仓库 3、使用Geotools的一些项目 二、Geotools架构 1、功能架构 2、Geotools支持的数据格式 三、Geotools科研热点 1、知网信息 2、百度学术 四、总结 前言 地理信息,智联万物。地理信息在我们的生活中…

《机器学习》—— OpenCV 对图片的各种操作(均值、方框、高斯、中值滤波处理)

文章目录 1、对有椒盐噪声的图片进行均值、方框、高斯、中值滤波处理2、给图像边缘增加边框3、对图片进行阈值化操作 1、对有椒盐噪声的图片进行均值、方框、高斯、中值滤波处理 均值滤波 cv2.blur是 OpenCV 库中的一个函数,用于对图像进行均值模糊处理。这个函数通…

【Mysql】通过Keepalived搭建mysql双主高可用集群

一、环境信息 主机名ip操作系统mysql版本VIP(虚拟ip)hadoop01192.168.10.200centos7_x865.7192.168.10.253hadoop03192.168.10.202centos7_x865.7 二、mysql集群搭建 两台节点,如果未部署mysql服务,部署文档请看【Mysql】mysql…

前端自动导入依赖

前言 开发中通常会有很多导入语句&#xff0c;如何确保一些通用的api和hook无需每次手动导入即可使用。 <script setup lang"ts"> import { ref, reactive } from "vue" import { useRoute, useRouter } from "vue-router" import { log…

C++——string类(1)

### string是C中的一种类&#xff0c;在标准库中的&#xff1b;可以直接对字符串进行一系列操作。 string类类型的构造 1、无参构造&#xff1a; string(); 定义string对象的时候不给值&#xff0c;这个string类的对象里面没有字符&#xff1b; #include<iostream> #in…

VsCode中Jupyter找不到内核的问题

问题描述 之前可以选择内核&#xff08;可能要先 “Python: 选择解释器”&#xff0c;也可能不用&#xff09;&#xff0c;并且是自己检测到 conda 环境中的 Python。 但是后来会突然找不到内核&#xff0c;点击选择内核&#xff0c;会在空白下加载很久&#xff0c;无果。 这…

MIPI联盟D-PHYv1.2规范阅读笔记二之物理层接口协议PPI

本文阅读自eetop.cn_mipi_D-PHY_specification_v1-2.pdf Logical PHY-Protocol Interface Description&#xff08;PHY物理层协议接口描述PPI&#xff09; PHY物理层协议接口被用于连接物理层和通信栈与更高层协议栈之间建立联系。 表 31 定义了物理层协议接口&#xff08;P…

day10JS-this的使用规则

1. this情况总结 开启严格模式&#xff1a; "use strict"; //开启严格模式 1.全局&#xff1a;非严格this--->window &#xff0c;严格 this--->window。 2.普通函数执行&#xff1a;函数名() 非严格this-->window &#xff0c;严格 this--->undefined…

全新的大语言模型Grok-2,最新测评!!

埃隆马斯克再次引发轰动&#xff0c;他旗下的xAI公司推出了全新的大语言模型Grok-2&#xff01; 最新的Grok-2测试版已经发布&#xff0c;用户可以在&#x1d54f;平台上体验小版本的Grok-2 mini。 马斯克还通过一种谜语般的方式揭开了困扰大模型社区一个多月的谜团&#xff1a…

C/C++ 包管理器 Conan 安装及使用

文章目录 Github官网文档简介安装 Conan 包管理器Conan 私有存储库创建 profile 文件添加远程存储库依赖包操作命令 Artifactory 私有存储库下载安装包&#xff08;推荐&#xff09;Docker 方式安装 Conan 官方示例 Github https://github.com/conan-io/conan 官网 https://…

零代码上手,工厂数据管理从未如此简单

在当今快节奏的工业环境中&#xff0c;工厂管理者们越来越依赖于数据分析来优化生产流程、提高效率和降低成本。然而&#xff0c;传统的数据分析工具往往复杂难用&#xff0c;且动辄需要高昂的费用&#xff0c;这让很多工厂望而却步。不过最近本人发现了一款非常实用的报表工具…

智能废弃瓶子垃圾箱:城市环境的绿色守护者

随着城市化进程的加速&#xff0c;生活垃圾的处理成为城市管理中的一大挑战。智能废弃瓶子垃圾箱的出现&#xff0c;不仅提高了垃圾回收的效率&#xff0c;还促进了资源的循环利用&#xff0c;成为智慧城市建设的重要组成部分。 目录 技术概述 核心功能 应用场景 环境与社会…

Java数据结构栏目总结

目录 数组与稀疏数组 队列&#xff1a;自己用数组模拟Queue 环形队列&#xff0c;取模【取余】实现. 单链表(LinkList) 双向链表&#xff08;Next 、Pre&#xff09; 单向环形链表 线性结构 数组与稀疏数组 稀疏数组&#xff0c;很多0值&#xff0c;可用于压缩 特点&a…

在 AMD GPUs 上进行图分析使用 Gunrock

Graph analytics on AMD GPUs using Gunrock — ROCm Blogs 图和图分析是可以帮助我们理解复杂数据和关系的相关概念。在这种背景下&#xff0c;图是一种数学模型&#xff0c;用于表示实体&#xff08;称为节点或顶点&#xff09;及其连接&#xff08;称为边或链接&#xff09;…

【CTF Web】BUUCTF BUU BRUTE 1 Writeup(弱口令+暴力破解+字典攻击)

BUU BRUTE 1 1 点击启动靶机。 解法 随便输个用户名。 试试 admin。 用 burp 抓包。 生成四位数字的字典。 导入字典到 burp。 添加载荷位置。 开始爆破。破解完成&#xff0c;密码&#xff1a;6490。取得 flag。 注意 如果破解得慢的话&#xff0c;记得要续期靶机。不然靶机…

算法工程师秋招面试问题总结

大模型分布式训练并行 一般有 tensor parallelism、pipeline parallelism、data parallelism 几种并行方式,分别在模型的层内、模型的层间、训练数据三个维度上对 GPU 进行划分。三个并行度乘起来,就是这个训练任务总的 GPU 数量。 1.数据并行 数据并行是最常见的并行形式…

2024.8.27 作业

1> 提示并输入一个字符串&#xff0c;统计该字符串中字母个数、数字个数、空格个数、其他字符的个数 #include <iostream>using namespace std;int main() {string s;cout << "请输入字符串>>>";getline(cin,s);int letter0,digit0,blank0,…

git 复制提交到另外分支上

查看提交id 在原分支上查看要复制的id git log切换目标分支 将刚才复制的id&#xff0c;在这个目标分支上执行复制命令 git cherry-pick <commit-id>其中是要复制的提交的提交ID 效果 新分支上未复制的提交&#xff1a; 新分支上已复制的提交&#xff1a;