深入浅出的描述聚集索引,非聚集索引,覆盖型索引的原理

这几天在看关于Mysql数据库引擎的书,里面提到了数据引擎如何操作聚集索引的,看的我是有点一知半解。索性就找了一番资料,好好研究一下聚集索引,非聚集索引,覆盖索引的区别。
其实在说到聚集索引,非聚集索引,覆盖型索引的之前,我们不妨回顾一下,我们平常在跟数据库打交道得时候会不会产生一些疑惑。
比如,
为什么建表得时候一定要创建主键?
为什么一提到提高查询速度得时候就会首先想到用索引,索引如何提高数据库得查询速度得?
在使用索引得时候有没有什么副作用?
我们在什么情况下会给俩个字段同时加一个索引?

这些问题,我们平常得时候可能只是会一闪而过得从脑海中冒出来,但是我们并没有真正得去深入思考。大部分得时候我们可能还只停留在"知其然而不知其所以然"的阶段。

希望我接下来的讲解,帮助你们更好的理解这些原理。

如果大家去查询资料的时候,会发现,网上对于索引原理的说法大部分都是这样的**「索引就像书的目录, 通过书的目录就准确的定位到了书籍具体的内容」**

额。。。。。。。,也不能说这句话不对,但是这样的说法给人的感觉就像问:为什么鸟会飞。而你回答“因为鸟长了翅膀”,这样的回答本身没有错,但是这只是就问题描述了结果而已,并没有解释清楚里面的缘由

回到刚刚的那个回答上,如果想了解索引的原理,就必须清楚什么是【平衡树】(非二叉),也就是我们常说得B+tree。目前大部分得关系型数据库都把平衡树当做数据表默认的索引数据结构的。当然,也有另外,也有数据库使用哈希桶来做为索引数据结构得,这个我们在这里暂不做讨论。

好了,现在我们开始解释第一个问题了,为什么建表得时候一定要创建主键。假如我们在创建表得时候没有创建主键得话,当数据库里面产生数据得时候,这些数据会全部无序得存放在磁盘上,一行一行得很整齐,但是如果我们需要查询这些数据得时候,因为数据是无序得,这样得话,是无法得到自己想要得数据。如果给表加上主键得话,这个时候表里面得数据就会按照主键的次序生成树状的结构,排连在我们的磁盘上,这个数据树,就是我们常说的平衡数。换句话说,这个时候整个表都变成了索引,我们查找数据的时候直接顺着树的树枝找到我们想要的数据。这种整个表是一个索引的情况,我们就称之为**【聚合索引】。**
这也就是为什么数据库表只有一个主键,因为数据库只能按照一个主键将数据生成平衡树的结构,同样的,一个表也只能有一个聚合索引。
假如我们将user表的id设置为聚合索引,执行一条查询的sql语句,用id做为查询的条件

 select name,age from user where id=100

我画了索引中平衡树的流程图,大概是这个样子。以InnoDB中平衡树为例,一般层级约有13层,大概可以处理2千万条数据。至于怎么算的,也不是我们本次讨论的重点,如*果大家想了解的话,可以看我另外一个博客*。红色的部分就是上面sql索引的运行轨迹,在执行sql语句的时候,先从根节点开始查,比如根节点接收100,然后开始在第二层节点中找包含100的区间,发现第一个节点范围是0200,正好里面包含了100,然后再往第三个节点查,直到查到存储100的那个节点,根据这个节点上索引的物理地址再找到数据,返回回去。
这样做的好处就是不需要对全表进行检索,我只需要按照一定的规律去查询,就会极大的减少IO和CPU的运行时间,在数据量巨大的情况下,这种效率的提升是几何级的。
在这里插入图片描述
但是索引有无望而不利的时候,在查询数据库时享受索引的便捷的时候,我们要承担这种便捷带来的另一种麻烦,就是在对数据写入的时候,数据库不得不去重新梳理一下树的结构,因为所有的数据全部按照规则进行排序,当增删的时候,会破坏树的平衡状态,为了保证平衡,我们需要花费额外的资源进行调整。这就是使用索引带来的负面效果。
在说完聚合索引之后,我们再来谈谈非聚合索引,非
聚合索引在平常的数据使用时,是非常频繁的。通过名字我们可以大概知道非聚合索引与聚合索引的区别,非聚合索引其实可以理解为在表中不唯一,其可以相互独立的索引模式。它与聚合索引的数据结构是一样的

我还以user表来举个例子,假如现在我想给name,age 这俩个字段加索引怎么办,但是聚合索引已经被Id给使用了,这个时候,我们就可以是用非聚合索引,分别是name和age各加俩个索引,而这俩个索引又是相互独立的。这个时候表里面就会出现2个独立其不相关的非聚合索引,加上刚刚创建的聚合索引,这个表里面就有3个索引。
非聚合索引与聚合索引除了存在区别之外,他们还有依赖的关心。非聚合索引查询的最终节点不会像聚合索引那样直接指向数据库的真实物理地址,它最终指向的是聚合索引的某个节点,然后在聚合索引中顺着这个节点,进行查询,直到返回真实的数。
假如已经创建好name和age索引后,我们执行下面的sql

select * from user where name="张三"

我们再假设张三对于的id正好是100,下面我画一下这条sql索引执行的原理。
在这里插入图片描述
从上图我们可以看到,当执行sql语句的时候,先执行name的索引,通过name索引最终会指向一个主键值,然后再拿这个主键值去聚合索引里面进行查询,最终返回我们想要的结构。
概况的的来说,不管如果进行查询,最终都会利用主键通过聚集索引来定位到数据, 聚集索引(主键)是通往真实数据所在的唯一路径。效率比单纯的聚合索引效率要低。
那有没有一种情况,跳过聚合索引就可以查询到我们想要的真实数据呢,当然是有的,这就引出了**“覆盖索引”的概念**。覆盖索引在我们平常也比较常用,我们经常使用复合索引和多字段索引查询就是覆盖索引的一种。我们都知道表中的某个字段被创建索引后,那这个字段里面内容就会同步到索引中,但是如果我们一个索引指定了多个字段的内容呢。
我们看一下下面的代码段

//创建索引
        create  index name_age_sex on user(name,age,sex);
 //执行查询
       select name from user sex="男"

执行的流程图大概如下
在这里插入图片描述
将name,age,sex三个字段值做为同一个索引存储
通过非聚集索引name_age_sex 查找sex等于“男”的叶节点的内容,然而, 叶节点中除了有user表sex值以外,name字段的值也在里面, 因此不需要通过主键去聚合索引, 直接取得叶节点中name的值返回即可。
但是我们平常在创建这类索引的时候要注意回表的情况。比如我执行下面的sql

select birthday,name,age from user age="男"

这条sql在查询的时候,就回进行回表,因为查询结果birthday内容并不在节点里面,所以数据库依然会通过主键id,再通过聚合索引返回真实的数据。这样的话,这条sql查询的效率依然低效。

好了,关于聚集索引,非聚集索引,覆盖型索引的大致流程,我就说这么多了。欢迎补充。

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值