mysql 聚簇索引和非聚簇索引_图文并茂,说说MySQL索引

点击上方 小伟后端笔记 ,选择 星标 公众号

重磅资讯、干货,第一时间送达

f2d935623cb6e5af14f47d27c0dea5da.png

作者:小小木的博客
来源:cnblogs.com/wyc1994666/p/10831039.html

开门见山,直接上图,下面的思维导图即是现在要讲的内容,可以先有个印象~e7eba49153828e5ee8240ac1eabd72b6.png

  • 常见索引类型(实现层面)
  • 索引种类(应用层面)
  • 聚簇索引与非聚簇索引
  • 覆盖索引
  • 最佳索引使用策略

1.常见索引类型(实现层面)

首先不谈Mysql怎么实现索引的,先马后炮一下,如果让我们来设计数据库的索引,该怎么设计?

我们首先思考一下索引到底想达到什么效果?其实就是想能够实现「快速查找」数据的策略,所以索引的实现本质上就是一个「查找算法」

但是跟普通的查找有所不同,因为我们的数据有以下特征:

「1.存储的数据是非常非常多的」「2.并且还不断的动态变化」

所以实现索引时需要考虑到这两个特点。我们需要找一个最合适的数据结构算法来实现查找功能。

下面一起看下常见的查找策略,如下图:

612d35bdd274bf1dbd7d3acdd145c268.png

由于前面说的两个特点我们首先排除静态查找的算法。

至于查找树,我们有二叉树和多叉树两种选择:

「二叉树」:如果先查二叉树的话,由于我们的数据量庞大,二叉树的深度会变得非常大,我们的索引树会变成参天大树,每次查询会导致很多磁盘IO。

「多叉树」:多叉树解决了了树的深度大的问题,那么我们到底选择B树还是B+树呢?

B树 摘自维基百科 https://zh.wikipedia.org/wiki/B%2B树

38a6b22a8444437a696e23faa1145fc7.png

B+树 摘自维基百科 https://zh.wikipedia.org/wiki/B%2B树

38f48cab294e7e68c9f3a2377b3b54a8.png

从上面图可知「B+树的叶子节点存放了所有的索引值」,并且叶子结点之间以链表的形式相互关联,所以我们只需从最左的链表遍历的话即可查找所有的值,最常见的用途就是范围查找,而B树则不满足这范围查找,又或者说实现特别复杂,所以Mysql最终选择了使用B+树实现这一功能。

1.1 B-Tree 索引(B+树)

先说明一下,虽然叫在Mysql官方叫做B-Tree索引,但采用的是B+树数据结构。

B-tree索引能够加快访问数据的速度,不需要进行全表扫描,而是从索引树的根节点层层往下搜索,在根节点存放了索引值和指向下一个节点的指针。

下面看下单列索引的数据怎么组织的。

create table User(
`name` varchar(50) not null,
`uid` int(4) not null,
`gender` int(2) not null,
 key(`uid`)
);

上面User 表给uid列创建了一个索引,那么往表里插入uid(96~102)的时候存储引擎是怎么管理索引的呢?看下面的索引树

5dadf0f8fde82df176da6c34657d7114.png

「1.在叶子节点存放所有的索引值,非叶子节点值是为了更快定位包含目标值的叶子节点」

「2.叶子节点的值是有序的」

「3.叶子节点之间以链表形式关联」

下面在看一下多列(联合)索引的数据怎么组织的。

create table User(
`name` varchar(50) not null,
`uid` int(4) not null,
`gender` int(2) not null,
 key(`uid`,`name`)
);

给User 表创建了联合索引 key(uid,name) 这种情况下他的索引树是如下图所示。

e3042f39573d02cd9847349da9565c79.png

特点跟单列索引一样,不同之处在于他的排序,「如果第一个字段相同时会按第二个索引字段排序」

「如何通过B-tree快速查找数据?」

e5a83207d204cf9e88af5d573dbc2ed0.png

对于InnoDb 存储引擎的B-tree索引,会按以下步骤通过索引找到行数据

  • 如果使用了聚簇索引(主键),则叶子节点上就包含行数据,可直接返回
  • 如果使用了非聚簇索引(普通索引),则在叶子节点存了主键,再根据主键查询一次上面 的聚簇索引,最后返回数据

对于MyISAM 存储引擎的B-tree索引,会按以下步骤通过索引找到行数据

  • 在MyISAM 的索引树的叶子节点上除了索引值之外即没存储主键,也没存储行数据,而是存了指向行数据的指针,根据这个指针在从表文件查询数据。

1.2 Hash 索引(哈希表)

哈希索引是基于哈希表来实现的,只有精确匹配所有的所有列才能生效。

也就是说假设有个hash索引 key (col1,col2) 那么每次只有 col1和col2两个字段都用才能够生效。因为生成hash索引的时候是根据一个hash函数对所有的索引列取hash值来实现的。

如下方图,有个hash索引key(name)

ea45cf55b0ed336f86111957f9368212.png

当我们执行 mysql> select * from User where name='张三'; 时怎么利用hash索引快速查找的?

  1. 第一步,计算出hash值,hash(张三) = 1287
  2. 第二步,定位行号,比如key=1287 对应的行号为3
  3. 第三步,找到指定行并且比较name列值是否为张三做个校验
66672dbf8140fb51afa01dc72a9f2b0d.png

2.常见索引种类(应用层面)

「主键索引」

create table User(
`name` varchar(50) not null,
`uid` int(4) not null,
`gender` int(2) not null,
 primary key(`uid`)
);

主键索引是唯一的,通常以表的ID设置为主键索引,一个表只能有一个主键索引,这是他跟唯一索引的区别。

「唯一索引」

create table User(
`name` varchar(50) not null,
`uid` int(4) not null,
`gender` int(2) not null,
 unique key(`name`)
);

唯一索引主要用于业务上的唯一约束,他跟主键索引的区别是,一个表可以有多个唯一索引

「单列索引」

create table User(
`name` varchar(50) not null,
`uid` int(4) not null,
`gender` int(2) not null,
 key(`name`)
);

以某一个字段为索引

「联合索引」

create table User(
`name` varchar(50) not null,
`uid` int(4) not null,
`gender` int(2) not null,
 key(`name`,`uid`)
);

两个或两个以上字段联合组成一个索引。使用时需要注意满足最左匹配原则!

还有其他不常用的就不介绍了~

3.聚簇索引与非聚簇索引

什么是聚簇索引?聚簇索引指的是他的 「索引和行数据」 在一起存储。也就是在一颗B+树的叶子结点上存储的不仅是他的索引值,还有对应的某一行的数据。待会儿看图便知。

「聚簇索引不是一种索引,而是一种数据存储组织方式 !!!」

crreate table test(
  col1 int not null,
  col2 int not null,
  PRIMARY KEY(col1),
  KEY(col2)
);

如上所示,表test 由两个索引,分别是主键 col1 和 普通索引 col2。那么这俩索引跟聚簇非聚簇有啥关系呢?

会生成一个聚簇索引和一个非聚簇索引(二级索引),也就是说会组织两个索引树。主键索引会生成聚簇索引的树 以及以col2为索引的非聚簇索引的树。

「InnoDb 将通过主键来实现聚簇索引」 ,如果没有主键则会选选一个唯一非空索引来实现。如果没有唯一非空索引则会隐式生成一个主键。

下面看下聚簇索引和非聚簇索引在索引树上数据是怎么分布的,图片摘自《高性能Nysql》

「下图是聚簇索引的数据组织方式。col1为主键索引的聚簇索引树」

「索引列是主键 col1」c8e4a76a731b7e93aa9c5dd815a3b4f6.png可以看出叶子结点除了存储索引值 列col1 (3994700)值 之外还存储了其他列的值,如列col2 (92813),如果还有别的列的话也会存储,或者换句话说聚簇索引树 在叶子节点上存储某个索引值对应的一行数据。

「下图是非聚簇索引(二级索引)的数据组织方式。」

「索引列是 col2」

372d99185bba48f962661c3c3095f7d1.png

与聚簇索引不同的是非聚簇索引在索引树叶子节点上除了索引值之外只存了主键值。而聚簇索引则存了一行数据。

假如有一条sql 语句 select * from test where col2=93;上面这条语句会经历两次从索引树查找过程

1.第一步从非聚簇索引的索引树上找到包含col2=93的叶子节点,并定位到行的主键 3 2.第二步 根据主键 3 在从聚簇索引定位包含 主键=3的叶子节点并返回全部行数据。

以上说的都是基于InnoDb存储引擎的,「MyISAM」是不支持聚簇索引的,因为他的数据文件和索引文件是相互独立存储的 「MyISAM」存储引擎的索引树的叶子节点不会存主键值,而存一个指向对应行的地址或者说是指针,然后再从表数据文件里去找,如下面图所示。

3984f1c362ff715643d8162bfe5ba9c6.png

结论:

  • 聚簇索引: 通常由主键或者非空唯一索引实现的,叶子节点存储了一整行数据
  • 非聚簇索引:又称二级索引,就是我们常用的普通索引,叶子节点存了索引值和主键值,在根据主键从聚簇索引查

4.覆盖索引

「覆盖索引就是指索引包含了所有需要查询的字段。」

create table User(
`name` varchar(50) not null,
`uid` int(4) not null,
`gender` int(2) not null,
 key(`uid`,`name`)
);

假如表 User有三个字段 User (name,uid,gender),且有个联合索引 key(name,uid)那么 执行如下面这条sql查询时就用到了 覆盖索引。

select name,uid from User where name in ('a','b') and uid >= 98 and uid <=100 ;

上面这条sql语句使用了联合索引 key(name,uid),并且只需查找 name,uid两个字段,所以使用了覆盖索引。覆盖索引有什么好处呢?先看一下下面这个图e3042f39573d02cd9847349da9565c79.png上面这个图就是 联合索引key(name,uid) 所对应的索引树,从图中可以看出,如果我们只需查询(name,uid)两个字段的话,从索引树就能得到我们需要查的数据。不需要找到索引值之后再从表数据文件定位对应的行数据了。

覆盖索引好处 1.避免了对主键索引(聚簇)的二次查询 2.由于不需要回表查询(从表数据文件)所以大大提升了Mysql缓存的负载

总之大大提升了读取数据的性能

5.最佳索引使用策略

最后在讲讲使用索引过程中的避坑指南

「独立的列」

独立的列不是指单列索引,而是指索引列不能是表达式的一部分或者是函数的一部分。

select * FROM test where col1 + 1 =100; // 不能是表达式一部分

select * FROM test where ABS(col1) =100; // 不能是函数一部分

「最左匹配原则」

假如有个联合索引 key (col1,col2)。那么以下查询是索引无效的

select * from test where col2 = 3;

select * from test where col1 like '%3';

对于最左匹配原则,大家想一下B+树的叶子节点的关联就差不多知道为啥需要最左匹配原则了,因为B+的叶子结点,从左到右以链表的形式关联的,索引我们查询的时候要么范围查询,要么有明确的左边一个开始的索引值,不能跳过或者不明确如 like '%XYZ'这种查询。

「索引值不能是null值」

单列索引有null值会导致索引无效 多列索引只要有个列有null值会导致索引无效

「使用聚簇索引和覆盖索引大大提升读取性能」

因为聚簇索引和覆盖索引的索引树上就有了需要的字段,所以不需要回表文件查询,所以提升了查询速度

「使用短索引」如果很长的字符串进行查询,只需匹配一个前缀长度,这样能够节省大量索引空间

58ec84dfe186e2def7822b2c614d44d8.gif推荐阅读:

  • 从传统Web框架切换到SpringBoot后的总结

  • 阿里云盘正式上架,附下载链接+邀请码

  • 换工作,关于面试的总结

  • 学会这个!微信支付能提现免费!

  • 为什么SimpleDateFormat不是线程安全的?

不开心就点点 在看 开心也要点点 在看 

↘↘↘

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

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

相关文章

mysql数据库日志截断,MySQL基础(十一):查询截取分析

下面是小凰凰的简介&#xff0c;看下吧&#xff01;&#x1f497;人生态度&#xff1a;珍惜时间&#xff0c;渴望学习&#xff0c;热爱音乐&#xff0c;把握命运&#xff0c;享受生活&#x1f497;学习技能&#xff1a;网络 -> 云计算运维 -> python全栈( 当前正在学习中…

component是什么接口_阿里高级技术专家:整洁的应用架构“长”什么样?

很多同学不止一次和我反馈&#xff0c;我们的系统很混乱&#xff0c;主要表现在&#xff1a;应用的层次结构混乱&#xff1a;不知道应用应该如何分层、应该包含哪些组件、组件之间的关系是什么&#xff1b;缺少规范的指导和约束&#xff1a;新加一段业务逻辑不知道放在什么地方…

php把1拆分成三份,【php】位运算如何拆分

举例&#xff0c;比如说下面可以组合成71|2|4; // 7那么比如我给一个15&#xff0c;怎么拆分成&#xff1a;1、2、4、8&#xff0c;或者是任意其他数&#xff0c;怎么进行拆分回答不熟悉php。可以先确定这个数占多少位&#xff0c;比如64或者32等。然后再左移位&#xff0c;按位…

20155202 实验四 Android开发基础

20155202 实验四 Android开发基础 实验内容 1.基于Android Studio开发简单的Android应用并部署测试; 2.了解Android、组件、布局管理器的使用&#xff1b; 3&#xff0e;掌握Android中事件处理机制。 实验要求 第24章&#xff1a;初识Android任务一&#xff1a;完成Hello World…

死信队列和延迟队列_在实践中使用延迟队列

死信队列和延迟队列通常&#xff0c;在某些情况下&#xff0c;当您有某种工作或作业队列时&#xff0c;有必要不立即处理每个工作项或作业&#xff0c;而是要延迟一些时间。 例如&#xff0c;如果用户单击一个按钮来触发要完成的某项工作&#xff0c;而一秒钟后&#xff0c;用户…

python的代码在哪写_python代码在哪里编写

编写python代码&#xff0c;可以在自带的ide中写&#xff0c;也可以使用第三方编辑器&#xff0c;下面介绍几款常见的python IDE 1. VimVim 可以说是 Python 最好的 IDE。Vim 是高级文本编辑器&#xff0c;旨在提供实际的 Unix 编辑器‘Vi’功能&#xff0c;支持更多更完善的特…

nio框架中的多个Selector结构

随着并发数量的提高&#xff0c;传统nio框架采用一个Selector来支撑大量连接事件的管理和触发已经遇到瓶颈&#xff0c;因此现在各种nio框架的新版本都采用多个Selector并存的结构&#xff0c;由多个Selector均衡地去管理大量连接。这里以Mina和Grizzly的实现为例。 在Mina 2…

js 编码 php解码,浅谈php和js中json的编码和解码

php中1)编码$jsonStr json_encode($array)2)解码$arr json_decode($jsonStr)echo json_encode("中文", JSON_UNESCAPED_UNICODE);添加参数&#xff1a;JSON_UNESCAPED_UNICODE即可。测试环境&#xff1a;PHP Version 5.5.36js中1. 编码var str obj.toJSONString()…

如果您在2015年编写过Java代码-这是您不容错过的趋势

去年我们有机会遇到的最有趣趋势的实用概述 在这篇文章中&#xff0c;我们将回顾构成我们2015年对话的5个主题和新发展。与其他许多年终总结保持较高水平的不同&#xff0c;我们将做一个更实际的操作不用流行语 。 好吧&#xff0c;没有太多*流行语。 与往常一样&#xff0c;对…

mel滤波器组频率响应曲线_了解二阶滤波器的奈奎斯特图

在之前的文章中&#xff0c;我介绍了奈奎斯特图&#xff0c;然后我们通过检查奈奎斯特曲线和截止频率与一阶无源滤波器之间的关系&#xff0c;更详细地探索了这些类型的图。在本文中&#xff0c;我们将查看二阶滤波器的奈奎斯特图。二阶过滤器当我说“二阶”滤波器时&#xff0…

CJOJ 免费航班

Description 小Z在MOI比赛中获得了大奖&#xff0c;奖品是一张特殊的机 票。使用这张机票&#xff0c;可以在任意一个国家内的任意城市之间的免费飞行&#xff0c;只有跨国飞行时才会有额外的费用。小Z获得了一张地图&#xff0c;地图上有城市之间的飞机航班和 费用。已知从每个…

java perl5compiler,Java中正则表达式使用方法详解(四)

3.2 HTML处理实例一下面一个任务是分析HTML页面内FONT标记的所有属性。HTML页面内典型的FONT标记如下所示程序将按照如下形式&#xff0c;输出每一个FONT标记的属性在这种情况下&#xff0c;我建议你使用两个正则表达式。第一个如图十一所示&#xff0c;它从字体标记提取出“&q…

java 缓存接口,java项目中,针对缓存问题的处理方式【接口中的处理方式】

1、在service包中&#xff0c;分别建立了关于缓存的一系列的接口、类等&#xff0c;封装到一个工具包中&#xff1b;临时缓存的接口(代码部分)&#xff1a;packagecom.tools;importjava.util.Date;public interfaceCacheTemplet {//设置添加永久缓存,(缓存唯一索引&#xff0c;…

【hh】我胡汉三又回来了

hh 差不多半年没来机房了&#xff0c;高一的都已经碾压我100题了 开始得比较晚&#xff0c;估计比高一的早两三个月吧&#xff0c;停了这半年落下了不少。 但是没有关系啊&#xff0c;学OI纯粹是好玩嘛&#xff0c;一开始报名的时候根本不知道有联赛这回事&#xff08;其实报名…

python爬取知乎标题_python爬虫 爬取知乎文章标题及评论

目的&#xff1a;学习笔记2.首先我们试着爬取下来一篇文章的评论&#xff0c;通过搜索发现在 response里面我们并没有匹配到评论&#xff0c;说明评论是动态加载的。3.此时我们清空请求&#xff0c;收起评论&#xff0c;再次打开评论 4.完成上面操作后&#xff0c;我们选择XHR&…

php curl 要安装pear,MacOS 安装pear

1、下载Pearcurl -O https://pear.php.net/go-pear.phar2、安装Pearsudo php -d detect_unicode0 go-pear.phar安装过程需要进行简单的配置&#xff0c;如下Below is a suggested file layout for your new PEAR installation. Tochange individual locations, type the number…

CentOS7 下调教mysql记实 之一

迁移数据库时遇到错误&#xff1a; Error Code: 1418. This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) 解释&…

java 映射数组_Java中的数组,列表,集合,映射,元组,记录文字

java 映射数组有时&#xff0c;当我对JavaScript的强大功能和表现力感到兴奋时&#xff0c;我发现自己错过了Java世界中的一两个功能。 除了lambda表达式/闭包或任何您想称为“匿名函数”的东西之外&#xff0c;它还对数组&#xff0c;数组&#xff0c;列表&#xff0c;集合&am…

知道接口地址 如何传数据_如何选显示器连接线?四种主流接口要知道

前两天家里电脑显示器的线坏了&#xff0c;火急火燎的买了根线&#xff0c;谁知道买回来之后接口不匹配&#xff0c;不能用。显示器为什么要有这么多接口呢&#xff1f;这些接口又有什么区别呢&#xff1f;必须把它搞清楚&#xff01;这不&#xff0c;经过我的不屑努力&#xf…

docker rabbitmq php扩展,Docker开启RabbitMQ延时消息队列

前言经常在开发中会遇到一些不需要同步执行的业务&#xff0c;那我们就需要用到消息队列来进行异步执行&#xff0c;但是对于某些业务就还需要用到延时的功能&#xff0c;比如订单支付超时关闭&#xff0c;那么这个时候我们就需要开启消息队列的延时功能&#xff0c;当然也有朋…