原理速读之数据库索引

索引是什么东西?学数据都会讲到索引,但是很多人可能和我一样刚开始对索引完全没有具体的概念只知道大概怎么使用。今天就帮大家对索引建立一个基本的具象概念。
要聊到索引,我们首先了解一下数据库的结构。
大家对数据库的数据结构的印象是什么样的?是几张表,每张表里面有很多行很多列组成的一个excel表格一样的东西?不是这样的这个是一些数据库视图工具展示出来的数据库的结构,并不是底层的数据结构,我们要回到底层的数据结构。当然底层的数据结构实在复杂,我们要快速理解没那个时间去深入研究,但是大家要有一个简单的印象。我们可以用JAVA里面的对象来进行类比。首先数据是存在磁盘上的,磁盘有一些坐标地址,用来给我们定位快速找到数据。有这么一个场景,我们建立一个有十个字段的JAVA对象,对象没有直接存数据,而是存的引用,我们通过这个引用找到这个对象在内存中的位置读取数据,结果发现里面存的是个字段也不是数据,还是引用,这是个引用又指向了10个内存地址,我们再继续找下去...如此下去最终找到了真正的数据。我们可以用这个JAVA的模型来理解数据库的结构。首先数据库是一个大的对象叫Database,这个对象里有个List存了50个Table对象的引用,每Table对象里有个List又存了50个Row对象的引用,每个Row对象里面有个 List又存了10个Column对象的引用,每个Column对象里面存了具体的数据。要注意的是这些引用在内存中的位置并不一定是紧挨着,也就是一个表中的第一行数据和第二行数据位置可能差了十万八千里。
我对数据库的结构有了大致的了解之后那我们就可以知道我们如果要查询,一个数据库里student表第十行第十列的数据我们该怎么办,我们首先找到Datebase取出Table列表循环遍历直到表名等于student取出,然后又取出这个表里的Row遍历找到rownum等于10的Row,然后。。。
这么一看取出一个数据真是太不容易了,而真实的数据库结构不太可能是这样,因为列表不是一种很高效利于查询的数据结构,遍历也是很低效的一种数据查询算法。
数据库为了提高数据查询的效率设置了其他的策略,索引就是其中之一。
玩个小游戏,有一个List里面装了1-100的数字,如果我想找到任意的指定数字,该怎么做?最简单的就是遍历,比如我要找到49,我循环这个列表,直到有数字等于49就行,这是一种策略但是并不高效,因为每个数字平均要50次判断才能找到。如果我这么来,给定一个数字,我首先判断这个数字跟50的大小比较,如果大于50,我在用来跟75比较如果大于75,我再用来跟87比较,如果小于87,经过这三次比较我再遍历75-87之间的数字跟它比较最终找到这个数字,这么一来我平均只需要进行1+1+1+10/2 = 8次数据查找。效率好像高了很多!而且数据量越大效率越高。这里用到的就是我们高中就接触过的一种算法,二分查找法。只需要一次判断就可以减少1/2查找范围,3次能减少1-1/8=7/8的查找范围,4次能减少1-1/16=15/16的查找范围,(n次能减少1-1/2^n的查找范围,)我们只需要在剩下的1/16数据中进行遍历就能找到数据,现在我们终于直到了为什么直接遍历是一种很低效的查找方法了吧。
索引就是利用类似的原理,索引index就是我们常说的目录。
这么个场景,新华字典常用字8000,的几百页厚,如果我们不做任何处理,需要我们去一页一页去翻找到我们想要字,那可太费时间了。所以我们的想办法。
我们首先要提取所有汉字都共有的一个属性,然后按照这个属性将汉字归类,然后设计一套查找方法。我们首先想到所有汉字都可以归属到某一个拼音里里面,比如 人 ren,我们就可以设计一个按照拼音进行检索的策略。但是所有汉字拼音不算音调也有120多种,还是太多了也难找。我们可以提取出拼音的首字母再多进行一次分类。我们这样,如果我要插人,我们通过一算法知道它的拼音是ren,然后我们遍历26个字母,找到r,r下面有个列表ran,rang,rong,ri,re,ren,rui...遍历找到ren,然后ren下面就有具体的汉字,再遍历找到对应汉字及页码。完成。是不是快多了?这个就是字典的索引。当然这个索引的结构还可以优化,比如在26个字母里遍历还是太多,我们要二分一下,首先查首字母是在M前面还是后面,然后再二分,进行3次二分之后还没找到也只剩下3个字母再遍历找到。这个索引的结构就是而二叉树(b树),一根树枝分出两个叉每个叉又分出两个叉。
数据库的索引就是类似的,只是稍微复杂点,首先数据先按照一定的算法归属到某一个类,类似拼音,当然类比较多不可能遍历,设计一个3-4层的二叉树,这个类的“首字母”进行几次查找,找到这个类,这个类上绑定有数据的“页码”。这一部分的索引是普通索引。这里找到的“页面”还不是数据,而是聚集索引,前面的普通索引上没有挂任何数据,而是为了找到聚集索引而设计的索引。如果一个表有1万行,聚集索引上要绑定1万条数据,不可能遍历,聚集索引还是二叉树,最后一层叉上绑定有数据。
有同学就问了,为啥要分两部分索引,为什么每次只分4层左右的叉,不一直二叉下去。因为”日取其半,万世不竭“,叉到一定程度这个叉就会变的非常庞大,很难维护,这个分叉的过程就会变的很难,所以进行几层叉以后,最后一层叉上不再分叉而是挂个列表,列表里面的元素再重新分叉,将一个层次很深的叉分两段,更有效率。
这就是索引的大概原理。知道这个我们就能理解一些索引的特性了。为什么一个表里的索引不是越多越好?因为在你查询之前,先要往表里插数据,插数据的时候就跟查询差不多,需要将数据按照按照查询的规则放到对应索引的归类里面。同样修改删除的时候也要按照对应的规则修改索引。如果一个表的索引非常多,查询会变快,但是构建索引和修改索引将变的非常复杂。 还有其他很多特性都可以从这里推导,不再详述。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值