Mysql索引(一) 索引作用及结构

一、什么是索引?

在了解索引之前,先来看看索引的作用。

举一个经常用到也很贴切的例子,就是书的目录,试想,如果书没有目录,让你去找其中一个章节的内容,你需要一页一页的翻,看看对应内容,才能找到;如果使用目录,你就能快速定位你想找的内容在第几页,然后直接去那一页寻找就可以了。

这里书的目录就看可以看做一个索引,有同样的功效,返回到我们的数据库查询就是,如果你要从一万条用户信息数据中查询名叫张三的用户信息,如果不用索引,那就只是能一次次获取每一条用户信息,分别进行对比,知道找到了名为张三的数据,这样发的情况最坏你要进行一万次,是非常耗时的;但是如果我们能够建立索引,同过几次查找就能够定位到名为张三的数据存放地址,就可以节约大量的时间。

现在再来看索引的定义:用于帮助Mysql高效获取数据的数据结构。

定义里面包含了两个重要信息,一个是作用,即高效获取数据,对应的其实就是我们的查询语句动作;第二个是索引是一种数据结构。

二、索引结构类型

既然说到索引是一种数据结构,那索引的结构类型肯定就不止一种,下面就先来看看常见索引的结构类型:

1.散列(哈希)

以散列表作为索引的实现原理在于:将设置索引的字段通过哈希函数计算得到的数值作为数据的存放地址;在查询数据时,只需要获取条件字段的id,经过哈希函数后直接得出数据存放的地址,获取数据,时间复杂度为O(1)。

举个例子:某表中有一万条用户数据,其中给用户名加上了散列索引,在进行数据存储的时候,比如存储一条数据,索引字段(即姓名)为“张三”,将“张三”输入自定义的哈希函数,得出的结构作为这条数据存储的地址,将次数据存入。所有的数据插入都按此形式进行,那么在进行读取数据时,只要知道了索引字段“姓名”后,输入哈希函数,直接得到该字段对应的数据存放地址,进行存取。

哈希函数看似时间复杂度为O(1),其实存在了很多的不足和弊端:

  1. 每次插入数据要进行哈希计算,这个会耗费时间
  2. 如果使用过的哈希函数不合适,那么将产生哈希冲突
  3. 对于单个数据的查询时间复杂度为O(1),但是对于批量查询,哈希索引就无能为力了。

如果有小伙伴对哈希表的结构及其相关方法不是很清楚,我也写了一篇关于哈希函数的博客,解释了哈希的数据结构、哈希函数及解决哈西冲突的相关办法,有兴趣的同学可以看看。

2. B树

在学习B树之前,先来看看二叉排序树。二叉排序树就是左边节点比根节点小,右边节点比根节点大,并且左右子树都是二叉排序树。下面就是一个二叉排序树:

    我们先试着用二叉排序树作为索引,看看是怎么实现的,就以上图为例,我有9条数据,以id作为索引,分别为1,3,4,6,7,8,10,13,14,把他们按照二叉排序树尽心存储。现在我要查询id为4的数据,流程为:

   首先查看第一个节点为8,大于目标值4,不满足,往下一层转到左子树进行

   左子树根节点为3,小于目标值,往下一层转到右子树

   右子树节点为6,大于目标值,往下一层转到左子树进行

   最后,找到为4的值,获取。

可以看到以上步骤经过了四次查询,最终得到结果,也可以看出这里查找的时间复杂度时O(log(2)N)。效率高于不设置索引时的   O(logN)。

   看似很理想,但是更进一步,如果向二叉排序树中插入一些数据,比如插有序的序列,那么在某些情况下,树就会产生退化情况,即下面这个样子:

    

变成了链表的形式,如果以这样的形式进行查询的话,那时间复杂度又回到了O(n)了。所以这里就要引入另外一种树,叫做平衡二叉树,在插入的时候同时调整这棵树,让节点尽可能的均匀分布。例如红黑树就是平衡树的一种:

红黑树可以在插入的同时调整平衡。其实调整平衡的目的刚才说了,不让他变成链表,这只是一种极端情况,更多的情况在于控制树的高度,刚刚讲到排序二叉树的算法复杂度是O(log(2)N),其实就是树的高度,所以只要降低了树的高度,那么相应的查询次数就减少了。

既然降低输的高度可以减少查询次数,那么除了使用平衡树以外,还有没有其他方法降低输的高度呢,这里就终于要引入B树了,其实B树就是平衡多叉树,将输的提升为多路(一个节点中存放多个数据),高度也就降下来了,如下图所示:

 

通过设置成多路来降低树的高度,从而减少查询次数。这里可能就会问,既然如此,那我将宽度设置越大是不是树就越低,那么查询次数就越小呢。理论上是如此的,在解释这个问题的时候我们先来看看,当将B树用作文件系统的索引进行查询,是怎么处理的。

文件系统和数据库的索引都是存放在磁盘上的,如果要对其进行处理,先要将其读取到内存中在进行,但问题在于内存有限,不一定能够一次性将所有内存加载完成。所以针对于这里的情况,设置的路数越大,那么需要一次性存入内存的数据量就越大,对内存的消耗就比较大。

针对于B树,每一次查询,都是获取一个节点里的内容放入内存,进行处理,处理完之后;然后在进行下一次的读取和处理,这就要求一个节点里面的数据不能超过内存的大小,就对B树的多路进行了限制。

3. B+树

      说完了B说,再来看看B+树,它是B树的改造版本:

 

 区别于B树,B+树主要有两点不同:

  1. B树中的节点中存放的是索引加上具体数据,而B+树的非叶子节点只存储了索引值,并且将索引值下趁,和具体的数据时存放的叶子结点中
  2. B+树的叶子节点有指针形成链表

     至于为什么要这样进行设计,这里的原因我想到了两点:

1)某个人说过(忘了谁了),若果一个值用到的话,根据概率论、数学原理、哲学、玄学……推算,他旁边的值被用到的可能性也就越大

2) 可以想一想B+树的应用场景。B+树一般用于数据库的索引,比如mysql的索引默认就是B+树。对于mysql的查询,我们大多数时间查询是查询多条,比如按照某字段排序后的一段数据。

以上两点都反映了一个问题,查询数据的时候我们不单单查询的是当前设定的值,还会查询与当前值附近的值、或者排序的前后值。如果使用B树的话,在查询到值之后,再查询附近的值还需要对树进行遍历、跨层访问等,但是B+树的所有数据都在叶子节点上,而且个叶子节点通过链表实现连续,只要找到首尾,就能通过链表将所有的数据取出。

比如针对上面的图,我要查询13到23,只要查到了13,就能按顺序在叶子节点的链表或获取剩下的值,但是B树却做不到这一点。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值