一、Mysql索引的底层数据结构与算法

Mysql索引的底层数据结构与算法

  • 前言
  • 一、索引数据结构
    • 为什么 MySQL 的索引要使用 B+ 树而不是其他树形结构?比如 B 树?
    • 为什么InnoDB存储引擎选择使用B+tree索引结构?
  • 二、索引分类
    • 思考:以下SQL语句,那个执行效率高?为什么?备注:id为主键,name字段创建的有索引,age普通字段
    • 一张表,有四个字段(id,username,password,status)由于数据量大,需要对以下SQL语句进行优化,该如何进行才是最优方案:select id,username,password from tb user where username ='itcast';
    • 思考:InnoDB主键索引的B+tree高度为多高呢?
  • 三、索引语法
    • 3.1 创建索引
    • 3.2 查看和删除索引
    • 3.3 索引提示
  • 聚集索引&聚簇索引&稀疏索引到底是什么
  • mysql为什么建议使用自增主键
    • 3.1 业务层面
    • 3.2 性能层面
  • 联合索引底层数据结构又是怎样的
  • Mysql最左前缀优化原则是怎么回事

前言

索引(index)是帮助MySQL高效获取数据的一种有序数据结构。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。

优势:

  • 提高数据检索的效率,降低数据库的成本,减少io交互
  • 通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗。
    劣势:
  • 索引列也是要占用空间的。
  • 索引大大提高了查询效率,同时却也降低更新表的速度,如对表进行INSERT、UPDATE、DELETE时,效率降低。

一、索引数据结构

数据结构学习网址

  1. 索引为什么不使用二叉树作为索引结构?
    二叉树缺点:顺序插入时,会形成一个链表,查询性能大大降低。大数据量情况下,层级较深,检索速度慢。如下图
    在这里插入图片描述

我们如果查询5这个值时,其查询了4次,这个还是数据比较少,如果数据比较多,那么就会形成很深的层级,查询性能大大降低。

  1. 那红黑树呢?
    在这里插入图片描述
    看起来,层级变少了,查询5这个值只用了2步,但是红黑树也是一种二叉树,在数据比较多,也会形成很深的层级,查询性能也会较低,只是比二叉树好点

看来层级越少,查询性能越好,那有没有什么数据结构,在大数据情况下,层次也很少呢。有,下面开始介绍B-Tree

  1. BTree又称多路平衡查找树,叶节点具有相同的深度,叶节点的指针为空所有索引元素不重复,节点中的数据索引从左到右递增排列
    在这里插入图片描述
    B+Tree,非叶子节点不存储data,只存储索引(冗余),可以放更多的索引叶子节点包含所有索引字段,叶子节点用指针连接,提高区间访问的性能

以一颗最大度数(max-degree)为4(4阶)的b+tree为例:

为什么 MySQL 的索引要使用 B+ 树而不是其他树形结构?比如 B 树?

因为 B 树不管叶子节点还是非叶子节点,都会保存数据,这样导致在非叶子节点中能保存的指针数量变少(有些资料也称为扇出)。
指针少的情况下要保存大量数据,只能增加树的高度,导致 IO 操作变多,查询性能变低

为什么InnoDB存储引擎选择使用B+tree索引结构?

相对于二叉树,层级更少,搜索效率高;
对于B-tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低;
相对Hash索引,B+tree支持范围匹配及排序操作;

二、索引分类

在这里插入图片描述
在InnoDB存储引擎中,根据索引的存储形式,又可以分为以下两种:
在这里插入图片描述
聚集索引选取规则:
如果存在主键,主键索引就是聚集索引。
如果不存在主键,将使用第一个唯一(unique)索引作为聚集索引。
如果表没有主键,或没有合适的唯一索引,则nnoDB会自动生成一个rowid作为隐藏的聚集索引。

聚集索引结构图如下
在这里插入图片描述
非聚集索引结构图如下
在这里插入图片描述

思考:以下SQL语句,那个执行效率高?为什么?备注:id为主键,name字段创建的有索引,age普通字段

select *  from user where id =10;
select * from user where name ='Arm';
select id,name from user where name ='Arm';
select id,name,age from user where name ='Arm';

第一个SQL:id是聚集索引,他查到10这个节点时,就可以直接获取他的row
第二个SQL:name是非聚集索引,他查到Arm这个节点时,他不会直接获取他的row,而是获取他的聚集索引,如10,然后通过其聚集索引值获取他的row
第三个SQL:因为name是非聚集索引,他查到Arm这个叶子节点时,可以直接获取id,不会去继续回表查询
第四个SQL:当查到Arm这个叶子节点时,可以直接获取id,但是获取不到age的值,所以他需要通过id,继续回表查询

一张表,有四个字段(id,username,password,status)由于数据量大,需要对以下SQL语句进行优化,该如何进行才是最优方案:select id,username,password from tb user where username =‘itcast’;

对username和password创建联合索引,如果只对username创建索引,那么会产生回表查询
在业务场景中,如果存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引,而非单列索引。

思考:InnoDB主键索引的B+tree高度为多高呢?

在计算机中磁盘存储数据最小单元是扇区,一个扇区的大小是512字节,而文件系统(例如XFS/EXT4)他的最小单元是块,一个块的大小是4k,而对于我们的InnoDB存储引擎也有自己的最小储存单元——页(Page),一个页的大小是16K

假设:一行数据大小为1k,一页中可以存储16行这样的数据。InnoDB的指针占用6个字节的空间,主键即使为oigint,占用字节数为8。

高度为2:

n8+(n+1)6=161024,算出n约为1170
1171
16=18736
高度为3:

1171117116=21939856 (约 2 千万)

三、索引语法

3.1 创建索引

如果只关联一个字段,那么就是单列索引,如果关联多个字段,那么就是组合索引‘

create unique index 索引名 on 表名(字段名,字段名,字段名)//创建唯一索引  create fulltext index 索引名 on 表名(字段名,字段名,字段名)//创建全文索引 create  index 索引名 on 表名(字段名,字段名,字段名)//创建普通索引 

当字段类型为字符串(varchar,text等)时,有时候需要索引很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘io,影响查
询效率。此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率。

create index 索引名 on 表名(字段名(n); //创建前缀索引

前缀长度n,可以根据索引的选择性来决定,而选择性是指杯重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高则查询效率越高,最高为1,这是最好的索引选择性,性能也是最好的。下面以字段email为例

select count(distinct substring(email,1,5))/count(*)from tb_user

3.2 查看和删除索引

show index from 表名 #查看索引drop index  索引名 on 表名 #删除索引

3.3 索引提示

索引提示,是优化数据库的一个重要手段,简单来说,就是在SQL语句中加入一些人为的提示来达到优化操作的目的。

在Mysql如果一个字段上存在1个以上的索引,那么Mysql会自己选一个索引生效

create index school_home_index on person(school,home)create index school_index on person(school)explain select * from person where  school = '海'

在这里插入图片描述
如果我们自己想指定索引生效,那么可以使用下面的语法

#建议使用索引school_index,所以有可能不用
select  *from person use index(school_index)where school = '海'#忽略索引school_index
select * from person user ignore index(school_index)where  school = '海'#强制使用索引school_index
select * from person user force index(school_index)where  school = '海'

聚集索引&聚簇索引&稀疏索引到底是什么

聚集索引(Clustered Index)、聚簇索引(Cluster Index)、稀疏索引(Sparse Index)是数据库中常见的索引类型。

  1. 聚集索引(Clustered Index)

    • 聚集索引是一种索引类型,它改变了数据在磁盘上的排列方式,使得数据行的物理顺序与索引键的逻辑顺序相匹配。换句话说,聚集索引中数据行按照索引键的顺序进行存储
    • 聚集索引只能有一个,因为它决定了数据行在磁盘上的排列顺序。如果表中已经有聚集索引,再创建新的聚集索引会导致表的重组,代价较高。
    • 聚集索引通常应用于经常需要范围查询(Range Query)或者按顺序获取结果的列上
  2. 非聚集索引(Non-clustered Index)

    • 非聚集索引与数据行的物理顺序无关,它将索引键与数据行的引用映射到一个独立的数据结构中。这使得非聚集索引的创建和维护成本较低。
    • 一个表可以有多个非聚集索引,因为它们不会改变数据行的物理顺序。
    • 非聚集索引通常用于经常需要单一值查找(Single Value Lookup)或者经常需要在列上进行排序的情况。
  3. 稀疏索引(Sparse Index)

    • 稀疏索引是一种优化索引结构,它仅记录部分数据行的索引信息,而不是每一行都有对应的索引条目。
    • 稀疏索引通常应用于数据分布不均匀,但又需要索引支持的列。通过只记录部分数据行的索引信息,可以节省索引占用的空间,同时保持索引的查询效率。
    • 稀疏索引在一些特定的数据库引擎中才会使用,例如 SQL Server 中的稀疏索引用于处理稀疏列(Sparse Column)。

总的来说,聚集索引、非聚集索引和稀疏索引是数据库中用于提高数据访问效率的重要工具,它们各自适用于不同的场景和需求。

mysql为什么建议使用自增主键

MySQL建议使用自增主键的原因有以下几点:

  1. 性能优化:自增主键是按顺序递增的,插入新记录时不需要进行排序操作,可以提高插入数据的速度。另外,自增主键也有利于索引的建立和查询优化。

  2. 唯一性:自增主键保证了每条记录的唯一性,避免了数据重复或冲突的情况。

  3. 简化数据维护:使用自增主键可以简化数据的维护和管理,方便进行数据的增删改查操作。

  4. 节省存储空间:自增主键通常是整型数据类型,占用的存储空间较小,可以节省数据库存储空间。

综上所述,使用自增主键可以提高数据库的性能、保证数据的唯一性、简化数据维护操作,并节省存储空间,因此在实际应用中建议使用自增主键。

3.1 业务层面

先说业务层面。

假设某个业务中的用户账号使用了自增 ID 做主键,你注意一下,我这里说的例子使用了自增 ID,但是这个 ID 被赋予了业务含义。

这个业务一直都运行的好好的。

突然有一天,公司拓展了新业务。

公司要求这个账号在新老业务上的权益不能相同,在新业务上从 0 开始计算。

根据这个需求,那么此时如果改造数据表的话,用户 ID 就不能是唯一的了,业务对唯一约束的要求变成了:account_id + business_id。

如何才能使用最小的成本,来达到业务改造的目的?

当然你可以说我们有许多方案可以用,比如新业务独立使用一张新表等等。

我们暂且不讨论其他的方案,如果当初我们没有赋予这个自增主键具体的业务含义的话,是不是问题就好解决了?

假设 account_id 只是一个唯一索引,那么我们在改造业务的时候,只需要把这个唯一索引变更为 account_id + business_id,就可以极大的减轻业务改造的成本。

因此在一般场景下,我推荐你使用无业务含义的自增 ID 作为主键。

3.2 性能层面

下面再从性能层面分析一下,这里我们使用一个生活场景来举例。

这样的场景在互联网公司中非常常见,比如购物、打车、支付等等。

这类业务有一个重要特征就是流水业务,数据热点非常集中,一般用户高频访问的数据就是最近一天、一周或一个月内。

现在我们假设你在 XX APP 看到购书满 100-50 的优惠券,仅限今天使用,然后你去抢了一张。

抢优惠券的过程分以下几步:

你点击抢券
系统在优惠券表中读取你是否有此优惠券
如果有,系统提示已领券
如果没有,查看库存
如果有库存,库存 - 1 并把领券信息写入优惠券表
在这个过程中,系统要反复读取和更新优惠券表。

如果这个表使用了自增 ID 并且数据按时间顺序递增,那么数据热点就集中在今天这个范围内。

那使用无业务含义的自增 ID 做主键会有什么好处呢?

读和更新都集中在一个范围内。

此时不管是 SELECT 还是 INSERT、UPDATE 语句都集中在表的尾部。

前面我们提到了 MySQL 有预读和刷新邻接页的特性,因此这部分热点数据的写入性能会相对较好,也能很好的缓存到 InnoDB buffer pool 中。

假设你使用了带有业务含义的主键,那插入的数据可能就会随机分布到表的各个位置,从而带来大量的随机读和刷脏页操作,拖累整个表的性能。

你可能会质疑说使用无业务含义的自增主键,会导致读取和更新时都需要走二级索引,而二级索引回表操作会有两个 IO。

如果只看单个语句的情况下确实是这样,但是互联网业务通常都是高并发的场景,我们分析问题要从点考虑到面。

通过使用自增 ID 这个特性,我们可以将活跃的数据集中到表的尾部,通过预读的特性将这条数据邻接的其他数据也 load 到 buffer pool。

那么日期比较靠近今天的优惠券信息就能缓存到 buffer pool 中,因此这部分热点数据的性能会维持在一个较佳的状态。

虽然二级索引回表会多出 1 个 IO,但是由于 buffer pool 的介入,整体看来 IO 的总量还是变少了。

假设没有使用自增 ID,我们的热点数据是离散分布在整个表中,首先 INSERT 是完全随机的,然后把热点数据全部缓存到 buffer pool 中也需要耗费更长的时间和更多的 IO,这会带来更多的性能下降。

因此我还是建议你使用无业务含义的自增 ID 作为主键。

联合索引底层数据结构又是怎样的

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Mysql最左前缀优化原则是怎么回事

因为索引就是按着顺序建成的

MySQL最左前缀优化原则是指在使用索引进行查询时,只有索引的最左边的列被使用,才能充分利用索引的优势。换句话说,如果一个索引是由多列组成的,那么只有查询条件中涉及到索引的最左边的列,索引才会被用到。

举个例子,假设有一个索引包含两列 (col1, col2),如果查询条件是 WHERE col1 = 'value' AND col2 = 'value',那么这个索引就能被充分利用。但如果查询条件是 WHERE col2 = 'value',那么这个索引就无法被利用,因为查询条件没有涉及到索引的最左边的列。

因此,在设计数据库表结构和索引时,需要考虑到最左前缀优化原则,尽量将经常用于查询的列放在索引的最左边,以提高查询性能。

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

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

相关文章

SQL如何利用Bitmap思想优化array_contains()函数

目录 0 问题描述 1 位图思想 2 案例实战 3 小结 0 问题描述 在工作中,我们往往使用array_contains()函数来进行存在性问题分析,如判断某个数是否在某个数组中,但是当表数据量过多,存在大量array_contains()函数时,…

【软件测试】测试用例设计方法

1. 等价类划分法1.1. 等价类划分法的定义1.2. 有效等价类和无效等价类1.3. 等价类划分法实例分析 2. 边界值分析法2.1. 边界值分析法的定义2.2. 边界点2.3. 边界值法实例分析 3. 判定表法3.1. 如何用判定表法设计测试用例3.2. 判定表法实例分析 4. 正交表法4.1. 什么是正交表4.…

批量美化图片,轻松实现多张图片描边,让图片瞬间焕发新生!

图片已成为我们日常生活中不可或缺的一部分。无论是社交媒体上的个人分享,还是商业宣传中的产品展示,高质量、精美的图片都扮演着至关重要的角色。然而,对于许多人来说,图片处理仍然是一个令人头疼的问题。现在,我们为…

商超物联网方案-Hotspot Service和客流分析方案概述

商超物联网方案-Hotspot Service和客流分析方案概述 场景概述 大型商场、大型综合体在相互竞争及线上消费的影响下,利润增长缓慢,迫切需要通过提供个性化服务提升顾客购物体验,促进利润增长。 向不同顾客推送其感兴趣的广告,不仅…

c++游戏小技巧16:实例1(地牢生成算法)

1.前言 (头图) (其实最开始是想写恶魔轮盘的,但没想到它竟然更新了) (等我有时间在更,最近很忙,玩第五玩的) 想法来源:房间和迷宫:一个地牢生成算法https://indienova…

机器学习(五)之损失函数

上面几节讲了监督学习和非监督学习的一些算法(目前还不完整,会慢慢补充哒) 如果文章内容有错误,欢迎小伙伴在评论区指出! 前言: 损失函数在机器学习中非常重要,直接关乎模型的好坏(so?学好它)…

STM32G474 CMAKE VSCODE 开发环境搭建

本篇博文尝试搭建 stm32g474 的开发环境 一. 工具安装 1. 关于 MinGW、OpenOCD、Zadig 这些工具的下载和安装见 JlinkOpenOCDSTM32 Vscode 下载和调试环境搭建_vscode openocd stm32 jlink-CSDN博客 2. 导出一个 STM32 的 CMAKE 工程,这里略过。 3. 安装 ninja …

matlab期末知识

1.期末考什么? 1.1 matlab操作界面 (1)matlab主界面 (2)命令行窗口 (3)当前文件夹窗口 (4)工作区窗口 (5)命令历史记录窗口 1.2 matlab搜索…

Elasticsearch:对 Java 对象的 ES|QL 查询

作者:Laura Trotta ES|QL 是 Elasticsearch 引入的一种新的查询语言,它将简化的语法与管道操作符结合起来,使用户能够直观地推断和操作数据。官方 Java 客户端的新版本 8.13.0 引入了对 ES|QL 查询的支持,提供了一个新的 API&…

Redis 实战2

系列文章目录 本文将从字典的实现、哈希算法、解决键冲突、rehash、渐进式rehash几方面来阐述 Redis 实战Ⅱ 系列文章目录字典的实现哈希算法解决键冲突rehash渐进式 rehash渐进式 rehash 执行期间的哈希表操作 字典 API总结 字典的实现 Redis 的字典使用哈希表作为底层实现&…

【大数据】学习笔记

文章目录 [toc]NAT配置IP配置SecureCRT配置PropertiesTerminal Java安装环境变量配置 Hadoop安装修改配置文件hadoop-env.shyarn-env.shslavescore-site.xmlhdfs-site.xmlmapred-site.xmlyarn-site.xml 环境变量配置 IP与主机名映射关系配置hostname配置映射关系配置 关闭防火墙…

分层图像金字塔变压器

文章来源:hierarchical-image-pyramid-transformers 2024 年 2 月 5 日 本文介绍了分层图像金字塔变换器 (HIPT),这是一种新颖的视觉变换器 (ViT) 架构,设计用于分析计算病理学中的十亿像素全幻灯片图像 (WSI)。 HIPT 利用 WSI 固有的层次结…

【matlab基础知识】(三)二维曲线绘制plot

x[-pi:0.0001:pi]; 选择较小步距 ysin(tan(x))-tan(sin(x));plot(x,y) 条件和函数值做一个点乘 x[-2:0.02:2];y1.1*sign(x).*(abs(x)>1.1)x.*(abs(x)<1.1);plot(x,y) 颜色&#xff0c;线形&#xff0c;曲线上的标志 由于0.01cosx波动太小&#xff0c;所以plotyy绘制多…

正在载入qrc文件 指定的qrc文件无法找到。您想更新这个文件的位置么?

打开Qt的ui文件&#xff0c;弹出提示框 如果需要用到qrc文件&#xff0c;选择Yes&#xff0c;再选择qrc文件所在的位置&#xff1b;如果不需要qrc文件&#xff0c;可以选择No&#xff0c;然后用普通文本编辑器打开&#xff0c;将“ <resources> <include location&q…

ARP欺骗使局域网内设备断网

一、实验准备 kali系统&#xff1a;可使用虚拟机软件模拟 kali虚拟机镜像链接&#xff1a;https://www.kali.org/get-kali/#kali-virtual-machines 注意虚拟机网络适配器采用桥接模式 局域网内存在指定断网的设备 二、实验步骤 打开kali系统命令行&#xff1a;ctrlaltt可快…

Zookeeper服务

一、什么是Zookeeper Zookeeper 是一个分布式应用程序的协调服务&#xff0c;它提供了一个高性能的分布式配置管理、分布式锁服务和分布式协调服务。它是 Apache 软件基金会的一个项目&#xff0c;被设计用来处理大规模的分布式系统中的一些关键问题。 Zookeeper的组成员关系&…

【C语言】——结构体

【C语言】——结构体 一、结构体类型的声明1.1、结构体的声明1.2、结构体变量的创建和初始化1.3、结构体的特殊声明1.4、结构体的自引用1.5、结构体的重命名 二、 结构体的内存对齐2.1、对齐规则2.2、结构体对齐实践2.3、为什么存在内存对齐2.4、修改默认对齐数 三、结构体传参…

VS Code 保存+格式化代码

在 VSCode 中&#xff0c;使用 Ctrl S 快捷键直接保存并格式化代码&#xff1a; 打开 VSCode 的设置界面&#xff1a;File -> Preferences -> Settings在设置界面搜索框中输入“format on save”&#xff0c;勾选“Editor: Format On Save”选项&#xff0c;表示在保存…

《Mask2Former》算法详解

文章地址&#xff1a;《Masked-attention Mask Transformer for Universal Image Segmentation》 代码地址&#xff1a;https://github.com/facebookresearch/Mask2Former 文章为发表在CVPR2022的一篇文章。从名字可以看出文章像提出一个可以统一处理各种分割任务&#xff08;…

C++ | Date 日期类详解

目录 简介 日期类总代码 | Date 类的定义 & 构造 & Print 类的定义 构造函数 & Print 比较类&#xff0c;如<、>、<...... 值加减类&#xff0c;如、-、、-...... 加减类具体分类 判断某个月有多少天 GetMonthDay 日期类 / &#xff08;- / -&…