索引底层实现原理

大家都知道,通过建立索引,能更加快速地查找到你想要地数据。那索引到底是怎么工作的呢或者说索引的底层实现是如何的?本文将进行探讨。

索引为什么不选用AVL树又或者说红黑树这样的数据结构来组织底层的数据呢?

首先要明确的一点是,索引是存储在磁盘的,用于DBMS的一个排序数据结构,以协助快速的查询,更新表中数据。明确了这一点之后,既然是存储在磁盘上,对于MySQL来说,server层在调用存储引擎API之后通过存储引擎取到数据之后是要加载到内存中来,再由执行器进行比较判断是否为所需要的数据。这就出现的磁盘IO,为了避免过多的磁盘IO造成的性能浪费我们有一个预读取的操作。(原因是:操作系统有一个局部性原理,就是说在你读取到某一条数据时,认为它周围的数据你可能有很大机率用上,所以规定一次磁盘IO读取的最小单位是页(注意:页是我们设计的逻辑单位,并不是实际上磁盘存储数据的单位),一页的大小在MySQL中一般是16KB。)每次从磁盘中读取数据也就是发生一次磁盘IO我们读取到的是16KB的数据。重点来了,而采用AVL树的形式组织这样的数据效果如图

 

AVL树本质上是一棵二叉树+平衡操作。我们将树的每一个节点大小设置成16KB。如果说我们存储了这样6个数据,由于每个数据都是都存放在一个节点中,就生成了6个节点,而每个节点16KB的大小容量显然被浪费了。再者假如我们现在想要获取到id值为37的那行数据,我们需要三次磁盘IO才能找到,这是很耗时的,尤其是在存储量极大的数据库表中。所以MySQL并没有采用AVL树作为底层数据的组织方式。

不建议在经常更新的字段上建立索引,因为更新操作会导致索引的结构发生改变,需要不断调整索引的数据结构

这是InnoDB存储引擎的架构图,其中有一个Adapative Hash Index这是InnoDB自带的,Buffer pool中存放了从磁盘中读取到的热点页,为了提高访问Buffer pool中热点页的效率而建立的Hash索引。但在我们建表的时候一般不会建立Hash索引,InnoDB都是用B+树索引。

下面来说困扰了我一段时间的几个问题

  • 索引是在哪建立的?索引存放在哪儿?索引不就是一个用B+树组织的数据结构,那具体是怎么存放的?

上图是对MyISAM存储引擎的数据(user_myisam.MYD)以及索引(user_myisam.MYI)存放的地方。当你执行某些查询操作的时候,如果用到了索引,首先你的SQL语句通过网络发送给MySQL 服务端,然后服务端对SQL语句进行词法,语法分析,以及语义分析,再进行权限检查和查询优化进而形成执行计划,最后交给执行器根据执行计划去调用存储引擎的API进而取出相应的数据。在这个取数据的过程中,(数据是存储在磁盘中的),如果用到了索引,就会从索引文件中读取索引并加载到server的内存中与想要获取的数据的索引值对比,如果没找到,将再次进行磁盘IO,读取索引值。

如果创建了索引,就会先在内存中按B+树的数据结构形式进行组织,然后再将组织好的数据写入到磁盘中。当需要用到时,再从磁盘中读取,加载到内存中进行比较查找。

下面来说说为什么不使用AVL树或者红黑树的原因:

首先,小伙伴们需要明确AVL树以及红黑树的性质及特点。下面我简单介绍一下,感兴趣的朋友可以用这个网站看一下,这两个数据结构插入删除的动态变化过程。https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

  • AVL树也叫平衡二分搜索树,就是在BST树的基础上增加了一个更为严格的性质,以及相关的旋转操作。AVL树要求每个节点左右子树的高度差不超过一,这就保证了搜索的高效性。其他的特性我就不一一说明了,这里我们探讨它为什么不适合作为索引的存储?

首先为了保证更少的磁盘IO,每次从磁盘读取到的数据都是以页(16KB)为单位的,所以我们通常以读一次最小的单位来作为索引树中一个节点的大小。当索引建立完成后,使用到索引的时候将会是很糟糕的,AVL树是二叉树,每个节点存放的只是索引值和数据的物理地址。这远远达不到16KB的大小,这就造成大量的内存空间的浪费,同时少量的节点会形成多层的树结构,每一层树结构的搜索都将会是一次磁盘IO。所以AVL树会导致查询效率特别低,因此不适用于索引结构的组织。下图是AVL组织的索引树

  • 红黑树在平衡性方面不如AVL树,但是最坏的情况是最长的那条路径是最短的2倍。和AVL树会出现的问题一样,也不适合用于索引结构的组织。

因此应运需求而生的B树和B+树出现了,以AVL树为基础但是要在一个节点存尽可能多的数据。这就是B树。一般称之为m阶B树,m表示Degree,就是一个节点有m个指针域(存放索引值指向的物理地址),m-1个数据域(存放索引值)。当数据数量=m时将向上分裂该节点。一分为3。具体的动画演示也可以参考上面的网站。这样就做到了一个节点存尽可能多的数据。B树只将索引值和物理地址在数据结构中保存了下来。真正的数据还要在另一个文件中存放。从下图,用B树组织数据带来的单个节点存储数据的极大提升。

而B+树则是索引和数据都放在一个文件中,和B树相比,B+树将所有的数据直接存放在叶子节点中并组织成一个双向循环链表。这样在做查询操作的时候就可以直接在一个文件中完成,减少磁盘IO的次数。下面这个图将看起来更直观

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值