MySQL 索引底层原理

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

索引是一种数据结构,数据结构有:二叉树(二叉查找树Binary Search Tree)、红黑树(Red Black Tree)、Hash表、B-Tree、B+Tree

索引详解:

1.假设索引采用二叉树数数据结构:

MySQL 索引底层原理_第1张图片

如图所示:我们建了一张表,一些个人数据,此时以age字段建一个索引,如果采用二叉树数据结构作为索引那么图如下:

MySQL 索引底层原理_第2张图片

此时如果进行查询:select * from user where age=29 ;

age为索引字段,会先去存储我们索引的数据页进行查询,29大于24,又小于31,很快找到29这个索引值,并且根据这个key值存储的磁盘文件地址值,再进行一次磁盘IO去查找这个地址存放的目标数据。如果age不是索引字段,则需要数据库一行一行数据去比对,比对6次以后才拿到目标数据,不停的进行磁盘IO,效率很低。

弊端:如果索引字段一直都是一种规律增加,树的高度会很高,而且查询效率依然很低,这种情况下,几乎变成了线性查找。如图:

MySQL 索引底层原理_第3张图片

2.红黑树 

此时红黑树就应运而生,可解决此问题,红黑树不仅具有二叉树的特性,还有自己的附加属性;

1.结点是红色或黑色。

2.根结点是黑色。

3.每个叶子结点都是黑色的空结点(NIL结点)。

4 每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)

5.从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点。

MySQL 索引底层原理_第4张图片

 这里不做深入讲解(因为我也不是专家);这里解决问题的方式,就是利用红黑树的自旋的特性,如果出现线性的情况,红黑树的节点会进行左旋转或者又旋转,来达到树状结构的自我平衡

简单理解如图:MySQL 索引底层原理_第5张图片

 旋转重新组成合理的树状结构,这样树的高度降低,查找的效率提高!例如主键:MySQL 索引底层原理_第6张图片

    在大数据量的情况下,红黑树依然会有性能问题,例如百万或者更多级别的数据,红黑树的高度依然会特别高,因为基本的特性就是二分查找。此时B-Tree就出现了,在纵向高度无法突破的情况下,只能考虑横向扩展,可考虑横向放的索引数据增加,让一个节点存放更多的索引元素,同时可以分更多的叉出来。

    对红黑树进行一定的改造之后,就可以支撑大数据量的查找,高度可控制在5以内。

   B-Tree : 叶节点具有相同的深度 ,叶节点的指针为空,节点中的数据索引从左到右递增排列。

MySQL 索引底层原理_第7张图片

MySQL的索引底层用的 B+Tree ,是对B-Tree的一个改造,实际上是一个多叉平衡树。

B+Tree : 非叶子节点不存储data,只存储索引,可以放更多的索引;同时叶子节点维护了顺序访问指针(双向指针),提高区间访问的性能。(所有的索引元素都是存储在叶子节点里面,如下图示)

MySQL 索引底层原理_第8张图片

 

      相关的索引数据只存储在叶子节点里面,这样做可以让非叶子节点能存储更多的索引,但也并不是说每一个节点索引可以无限存储,因为最后都是会放到内存里面去进行运算查找,需要考虑内存及成本。目前MySQL的每个节点分配的空间可以通过命令查看:

SHOW GLOBAL STATUS LIKE 'INNODB_page_size';

MySQL 索引底层原理_第9张图片

 每个节点分配了16384个字节,也就是16KB的空间。

 

 那么存储索引的时候,一个节点最多能存储 16k/14B=1170个索引;叶子节点由于存储了索引及相关的数据,叶子节点 假设每组大小为1KB则一个叶子节点可存16个数据;如图所示 ,B+Tree高度为3的时候,理论上所能存储的数据量则为:1170*1170*16=21902400 两千万的数据量。也就是千万级别的数据量情况下,树的高度只有3,效率很高。

       Hash表:MySQL目前支持BTREE 和 HASH 两种索引方法,也就是两种索引存储数据结构,用Hash散列算法,key为索引值,value为存储数据的磁盘指针数据,同hash算出来的值进行映射,这样进行单条数据查找的时候会非常快,但是一般数据库用的很少,虽然在进行单一数据查找很快,但是hash无法支撑范围查找,范围查找的时候性能会非常低,所支持的场景单一。

       B+Tree 叶子节点维护有指针,右边元素的索引值都是大于左边的,所以当出现范围查找的时候,只需要找到对应的索引即可找到想要的结果集。顺着指针依次将后面所有的元素放到结果集里面,如果没有这个指针,则会每次都要再从根节点开始去找对应的索引找数据。   


不同的存储引擎,底层用B+Tree存储的时候,存储文件还有一点点区别

1.MyISAM的索引文件和数据文件是分离的(非聚集)

     磁盘上文件存储的时候,一张表至少三个文件,*_myisam.frm 表结构文件,*_myisam.MYD 表数据行文件,*_myisam.MYI 存储表数据的索引(B+Tree结构)。如果是这种类型的存储引擎,命中索引的时候先去 MYI文件中定位到这个索引,找到这个文件中存储的对应的磁盘文件指针,此时(叶子节点的data存储的是这个索引所对应的数据所在磁盘的所在行的文件指针),再去MYD文件中找到对应的数据,放到内存中去。

2.InnoDB的索引实现(聚集),支持事务,用的最多

    表数据本身就是按B+Tree组织的一个索引结构文件, 聚集索引-叶子节点包含了完整的数据记录

     一张使用InnoDB存储引擎的表,对应的文件有两个*_innodb_lock_frm (表结构文件)、*_innodb_lock_ibd(存储了索引+数据),(叶子节点里面的data 存储的是相应的行数据),比MyISAM少了一次磁盘IO。

     为什么InnoDB必须有主键,且推荐使用整型自增主键?

     1.如果不设置主键依然可以建表存储,但是底层会自动识别一个字段或者单独建立一个字段作为主键。 

    2.非主键索引,data存储的不是具体的行数据,而是主键索引

    3.用整型是因为查找索引的时候会经过很多的比较运算操作,这种情况下其他类型效率不会很高,比如用UUID的时候,字符串进行比较,需要逐位对比,如果英文跟数字又需要转位ASCII码来比较大小,影响效率。

    4.如果非自增主键,就会存在后续新增的数据可能在之前的节点的中间,由于data存储的行数据,一个节点16KB大小,如果本来这个叶子节点已经这么大了,现在又要新增一个主键索引和数据,之前的叶子节点就需要做一个数据页分裂操作,才能将新增的数据加进去,影响性能。用自增,则可以保证每次新增的数据都是在后面,不会遇到数据页分裂的情况。

     为什么非主键索引结构叶子节点存储的是主键值?(一致性和节省存储空间)

你可能感兴趣的:(java小细节,b树,数据结构,java)