InnoDB索引查询原理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了InnoDB索引查询原理相关的知识,希望对你有一定的参考价值。
参考技术A 如果没有建立索引的话,执行查询的时候,会将硬盘里面的数据页,加载进去buffer pool,然后遍历查找,查找完后,再去加载新的数据页,一直到遍历完所有的数据页,这样效率是非常低的。时间复杂度是O(n)。数据在数据页里面的存储是按照主键从小到大排列的,数据页内的数据行通过单向链表链接在一起。如下图所示:
这时候,我们查数据的话,是不知道我们的目标数据是在哪个数据页里面的。例如要找id = 5的这条数据。 是不知道这条数据是在数据页1还是在数据页2的。这时候我们需要一个东西来标记提示,每个数据页里面存在什么数据。 例如:
这个结构叫做页目录,其实是和数据页放在一起的,是数据页的一部分。页目录还记录着对应主键的数据,存在于数据页的物理位置。
那这时候我们去页目录里面找id=5的数据,是怎么找的呢?由于页目录还是放在数据页里面,所以还是需要将数据页加载到buffer pool再进行查找。将数据页1加载到buffer pool,然后找数据页的页目录,发现id最小=1, 最大=3 ,发现不在本数据页内。
继续加载下一个数据页2 , 然后查找页目录,id最大=4,最小=6,数据在这个数据页的范围内, 然后继续进行二分查找,直到找到id=5这个数据目录,然后根据这个目录给出的id=5这条数据的物理地址,获取到这条数据。
这时候,虽然不用在数据页里面一条一条遍历查找了,但是还是需要不断加载数据页到buffer pool进行查找,时间复杂度还是O(n)。
可以考虑将页目录抽取出来,独立做成一个数据结构,独立于数据页,这样就不用加载数据页进buffer pool就可以用页目录进行查找了。抽取出来的页目录暂时叫做主键目录,抽出页目录出来的时候,进行一下优化,不需要将每个目录的所有id都列出来,只需要将最小的id列出就可以了,这样也可以确定id大小的范围。如下图:
这时候,我们需要查找主键id=5的数据的过程,对比主键目录的第一条记录和第二条记录,id是否大于等于1小于4,否。那么就id=5这条数据是在第二条记录里面的,因为主键目录只有2条记录。根据主键目录,就可以确认数据是在数据页2里面。这时候,加载数据页2到buffer pool。然后对数据页2的页目录进行二分查找,找到id=5这条数据的位置,然后获取id=5这条数据,
这个主键目录,可以叫做索引,是一个基础的一个概念,但不是真正的完整的InnoDB的索引。
随着数据越来越多,索引条目(一条最小id和数据页对应的记录)也会越来越多,不可能将所有的索引条路放在一个索引目录里面,所以需要分开存储。当索引目录一分为二的时候,我们就可以将这两个索引目录称为索引页,和数据页同一个道理。如下图:
按照当前这样的索引页切分方式的话,查询效率也会很低的。先加载索引页1到内存,然后用二分查找,如果没有找到再加载索引页2到内存,进行二分查找。如此往复,一直到查找数据。 最坏情况下,就要将所有的索引页都找一遍,也就是遍历了。时间复杂度又变成O(n)了。
在数据有序的情况下,进行查找,使用树结构,效率会得到非常大的提升。如下图所示:
这时候,如果要查id=5这条数据:加载索引页1 ,然后发现id最小的索引条目是10,比5大,所以去索引页的左子树索引页2里面找,二分查找发现id=5这条数据在最后一个条目,在数据页2,然后就去数据页2里面进行二分查找,获取到id=5这条数据。这样,数据页3就永远不会加载,大大提升了查询效率。
如果采用这样的结构,就会容易造成树的层级过多,降低查找的效率。 例如,每个数据页只能存10个索引条目,索引页1存了10条索引目录,分别是1-10。那么再增加10个索引条目的时候,就只能再增加一个索引页2(索引条目是11-20),索引页2只能做索引页1的右子树,这时候,再增加一个索引页3(索引条目是21-30),那么索引页3就只能作为索引页2的右子树。当前树就有了3层。每个索引页的数据范围只能是10个,降低了二分查找范围。
这时候,如果要找id=25的数据,就需要先到索引页1,进行二分查找,因为25比10大,所以去索引页2里二分查找,发现还是比20大,再去索引页3里面二分查找,最后在索引页3里面找到。 这样就经理了3次二分查找。
可以再进行一层抽象:树的叶子节点,才实际存储索引条目,其他节点,只存储子节点的最小id,和子节点的指向。如图:
如果按照这样的数据结构来进行存储,查找的效率就大大提升了。 例如现在要找id=95的数据。 那么,只需要加载索引页1 , 然后二分查找,发现95大于60。所以数据在索引页4,然后去索引页4里面进行二分查找,就可以找到id=95的数据,然后找到对应的数据页6 。 然后再去数据页6的数据目录上进行二分查找,找到id=95对应的数据所在的物理位置。
这样的结构,就可以增大每次二分查找的数据范围,减少二分查找的次数。提升二分查找的效率。
到此,索引的结构就如上图所示,这个就是一个概念上的索引的结构了。
以上是关于InnoDB索引查询原理的主要内容,如果未能解决你的问题,请参考以下文章