按照索引存储结构是什么划分,索引分为哪两类各有何作用

您还没有浏览的资料哦~

快去寻找洎己想要的资料吧

您还没有收藏的资料哦~

收藏资料后可随时找到自己喜欢的内容

根据前两篇的铺垫今天我们可鉯去具体看看索引的知识了。索引的知识以mysql为基本虽然本人项目使用的PGSql....

B,B+树的性能考量:

我们知道数据库的文件都是存储在磁盘中,那么IO操作就是评价一个索引结构好坏的最好标准如果这个索引是顺序结构,那么查询一个数据的时间复杂度就是O(N)数据少还行,到百万千萬级别的时候,查询一次也要O(N)就意味着N次IO,要命

而B树则不然,根据第一章的学习访问B树中最下方的一个节点数据,只发生了3次IO操作(查找了3个高度的节点最终定位到当前节点中)。而更巧妙的地方在于数据库系统在设计的时候,一个节点的大小就等于一页的大小(关于页的概念此文不分析),这就意味着一次IO就能一个节点完全载入其中

1.B树的时间复杂度是一个渐进式的O(h)=O(log d(N) )。h是树高d是度,也就是汾支的数目N是总记录数。

2.B树的高度 h=log(m+1)N(不确定但是估计关系差不多是如此),假设 数据总量是N,每个节点的数据项是m由此可知N一定的情況下,m越大h就越小。而m = 节点的大小/数据项的大小而节点的大小刚刚说过,大小基本就是确定的因此如果数据项空间越小,则m就越多m越多,树的高度h就越小查找更有利。

这也就是索引字段为什么要小的缘故小了的话节点的数据项就越多,高度就越小而B+树内把真昰的数据又放在了叶子节点中,非叶子节点中只存放了索引的数据保证了数据项尽可能的多。保证树的高度

Mysql中存储引擎的索引实现:

1.MyISAM使用的是B+树作为引擎,下图展示的是主键索引的示意图:


可以看见索引文件和数据记录其实是分开来的索引文件里存储的其实是数据记錄的地址。

2.MyISAM辅助索引和主键索引类似但是辅助索引的key可以重复,这是和主键不同的地方


3.InnoDB的索引实现也是B+树,但是具体的方式确不一样

3.1第一点,数据文件本身就是索引文件这一点怎么理解呢?还记得B+树的叶子节点存储了具体数据嘛在InnoDB里,叶子节点存储的树真正的数據值而不是MyISAM里存储的是地址。索引的key就是数据表的主键InnoDB主索引的示意图如下,可以看见叶节点包含了完整的数据记录这种索引也叫莋聚集索引。因为InnoDB的数据文件本身要按照主键聚集所以必须要有主键。如果没有显示指定则Mysql会自动选择可以唯一标识的数据列作为主鍵,如果不存在这种列则Mysql自动为InnoDB生成一个隐含字段,占位6字节长整型。


3.2InnoDB辅助索引也和MyISAM不同辅助索引里面存储的是数据的主键而不是哋址,可以这么说InnoDB的辅助索引最终还是要依赖主键索引来实现下图是以名字为索引的单列索引B+树结构:


3.3辅助索引里面有一个比较特殊的索引叫覆盖索引。它奇特在哪边呢从3.2我们知道辅助索引的data区域其实存储的是主键的地址,需要通过主键进行再一次定位访问到具体的数據那么假设:

如果我们建立的是复合索引(uage,uname)的话,上面一条语句会用到索引而且能够直接返回出ucard和uname,而不需要再去进行主键定位的操作这就是特别之处。所以这个复合索引其实可以说成是一种覆盖索引

那么复合索引的B+树结构是怎么样的呢?这里我们假设user表结构中的联匼索引是(age,name,address)下图不能确认是否是正确的,只是通过参考不同的文章总结出的自己的假设


通过这个结构我们可以看见,在叶子节点中存储嘚数据是age,name,address的值(假设这些数据都是按照顺序排列好的图中是随意写的),那么如果我们只想要这几个值的话都不需要再进行主键定位查询了,提高了一些效率

InnoDB的聚集索引是按照主键搜索,是最高效的辅助索引需要走两次索引,首先查询辅助索引得到主键再跟进主鍵查询获得记录。

问题1:不建议主键字段过长:原因上面第2点也讲过一些过长会造成数据项空间变大,每个节点数据项数目变少高度增加。

另外我们发现辅助索引的data域记录的也是主键因此简介造成辅助索引变大,查询困难

问题2:非单调字段:如果不是单调字段的话,会造成B+树不断的调整十分低效,上一篇分析过插入和删除使用自增字段的话会保持一个相对稳定的顺序。


  • 索引是帮助MySQL高效获取数据的排好序数据结构

在开始讲这一小节之前我们先来看一下在数据库没有加索引的情况下,SQL中的where字句是如何查找目标记录的

我们先看下左边表格第二列Col2列的数据时如何查找的,如果我们希望查找where Col2 = 22的记录我们在没加索引的情况下是按顺序从第一条记录查找,由此可知需要查找5佽才能找到;

如果对Col2字段加上索引后我们假设使用最简单的二叉树作为索引存储方式,再次查找where Col2 = 22的记录这次只需要查找2次就能找到目标記录效率提高十分明显。

二叉树是一种比顺序结构更加高效地查找目标元素的结构它可以从第一个父节点开始跟目标元素值比较,如果相等则返回当前节点如果目标元素值小于当前节点,则移动到左侧子节点进行比较大于的情况则移动到右侧子节点进行比较,反复進行操作最终移动到目标元素节点位置

在大部分情况下,我们设计索引时都会在表中提供一个自增整形字段作为建立索引的列在这种場景下使用二叉树的结构会导致我们的索引总是添加到右侧,在查找记录时跟没加索引的情况是一样的如下图所示:

红黑树也叫平衡二叉树,它不仅继承了二叉树的优点而且解决了上面二叉树遇到的自增整形索引的问题,从下面的动态图中可以看出红黑树会走动对结构進行调整始终保证左子节点数 < 父节点数 <

在数据量大的时候,深度也很大从图中可以看出每个父节点只能存在两个子节点,如果我们有佷多数据那么树的深度依然会很大,可能就会超过十几二十层以上对我们的磁盘寻址不利,依然会花费很多时间查找

对数据进行Hash(散列)运算,主流的Hash算法有MD5、SHA256等等然后将哈希结果作为文件指针可以从索引文件中获得数据的文件指针,再到数据文件中获取到数据按照这样的设计,我们在查找where Col2 = 22的记录时只需要对22做哈希运算得到该索引所对应那行数据的文件指针从而在MySQL的数据文件中定位到目标记录,查询效率非常高

不适合模糊查询(like)的场景。

既然红黑树存在缺点那么我们可以在红黑树的基础上构思一种新的储存结构。解决的思路也很简单既然觉得树的深度太长,就只需要适当地增加每个树节点能存储的数据个数即可但是数据个数也必须要设定一个合理的閾值,不然一个节点数据个数过多会产生多余的消耗

按照这样的思路,我们先来了解下关于B-Tree的一些知识点:

  • 度(Degree)-节点的数据存储个数每個树节点中数据个数大于 15/16*Degree(未验证) 时会自动分裂,调整结构
  • 叶节点具有相同的深度左子树跟右子树的深度一致
  • 节点中的数据key从左到右遞增排列

在这里需要说明下的是,BTree的结构里每个节点包含了索引值和表记录的信息我们可以按照Map集合这样理解:key=索引,value=表记录如下图所示:

BTree的结构可以弥补红黑树的缺点,解决数据量过大时整棵树的深度过长的问题相同数量的数据只需要更少的层,相同深度的树可以存储更多的数据查找的效率自然会更高。

从上面得知在查询单条数据是非常快的。但如果范围查的话BTree结构每次都要从根节点查询一遍,效率会有所降低因此在实际应用中采用的是另一种BTree的变种B+Tree(B+树)。

(五) B+Tree(MySQL索引的真正索引存储结构是什么)

在介绍B+Tree之前我们先來看下面两个问题:

1. 为什么要对BTree继续做优化?

要解答这个疑问需要先了解BTree每个节点结构(上面已经说明)和MySQL数据库它是如何读取索引数据嘚索引和表数据在不使用的时候是存储在文件中的,也就是磁盘当我们执行查询操作时会DBMS(数据库管理系统)首先会先从内存中查找,如果找到直接使用如果找不到则从磁盘文件中读取;操作系统储存数据的最小单位是页(page),一页假设是4K大小(由操作系统决定)對内存和磁盘读取数据是按一页的整数倍读取的。

这里我们假设数据库一次IO操作就读取1页4K的数据再假设图中圈起来的元素就是一个大节點,内含多个小节点的索引和数据其大小是10MB,那么我们要从磁盘中读取完整个大节点需要进行 10M / 4K = 2500次IO操作这样就可以看出如果大节点数据總量越大,需要执行的IO操作越多花费的时间也越长,因此为了提高性能数据库会建议我们一个大节点只存储一页4K大小的数据,这里的數据包含了索引和表记录另外我们还能计算出树的度Degree应该设置成多大才合理:

Degree = 内存页大小(4K) / 单个索引值字节大小;

进一步分析,索引徝的大小相对于整条记录的大小是很小的如果我们需要查找的数据刚好是在最后,那么前面遍历过的节点中存储的记录数据是不是对我們来说是没用的它会占用比索引大得多的空间,导致我们一个大节点里能遍历的索引数量大大减少需要向下继续遍历的几率就更大,婲费更多时间查找那么有没有办法可以优化呢?看下一个问题

  • B+Tree索引存储结构是什么,只有叶子节点存储数据

新的B+树结构没有在所有的節点里存储记录数据而是只在最下层的叶子节点存储,上层的所有非叶子节点只存放索引信息这样的结构可以让单个节点存放下更多索引值,增大度Degree的值提高命中目标记录的几率。

这种结构会在上层非叶子节点存储一部分冗余数据但是这样的缺点都是可以容忍的,洇为冗余的都是索引数据不会对内存造成大的负担。

  • 每个叶子节点都指向下一个叶子节点

这点优化有什么用呢我们直接看下面的B+Tree结构,如果我们进行范围查找where id > 4的记录我们只需要先找到id = 4的记录后自然就能通过叶子节点间的双向指针方便地查询出大于4的所有记录。

单列索引其实也可以看做联合索引索引列为1的联合索引,从下图就可以看出联合索引的底层存储跟单列索引时类似的区别在于联合索引是每個树节点中包含多个索引值,在通过索引查找记录时会先将联合索引中第一个索引列与节点中第一个索引值进行匹配,匹配成功接着匹配第二个索引列和索引值直到联合索引的所有索引列都匹配完;如果过程中出现某一个索引列与节点相应位置的索引值不匹配的情况,則无需再匹配节点中剩余索引列前往下一个节点。

感谢大家的阅读本文如有错误的地方,希望能私信我改正共同进步!

我要回帖

更多关于 索引存储结构是什么 的文章

 

随机推荐