首先索引是帮助MySQL高效获取数据的排好序的数据结构。那么为了搞清楚原因,我们首先简单说一下几种索引结构:
- 二叉树 二叉树是一种每个节点最多有两个子节点的树结构,二叉树中的每个节点只能存储一个关键字和数据,因此需要更多的节点来存储相同的数据量。
如上图,col2,使用二叉树进行索引,比如如果要查找值为89的行,那么只需要两次I/O操作,但是如果对col1进行索引,那么二叉树则无法达到很好的平衡,将成为一个只有右侧节点的链表,若想查找值为6的行,仍然需要进行6次I/O操作。
- 红黑树 红黑树具有良好的平衡性,查询效率较高,且适用于内存中的数据结构。但是红黑树与二叉树类似,每个节点只存储一个关键字和数据,所以,如果想要存储更多的数据量,则需要更多节点,更大的高度,此时不但会增加内存开销,随着数据量的增加,I/O次数也会相应增加。同时,红黑树中的平衡调整会涉及到节点的旋转操作,这些操作需要在磁盘中进行,因此红黑树的平衡调整会涉及到更多的磁盘I/O操作,会影响索引查询的效率。
- Hash 表 Hash 表数组+链表来存储索引的一种数据结构。与HashMap类似。对索引进行hash 来确定索引位置,并针对hash冲突的数据进行链表存储处理。每一个索引位置存储的是索引值及索引行所在的物理地址。该表结构能够一次I/O快速定位某个索引所在数据行。如下图,但是如果想要进行范围查询,那么该索引结构将无能为力。
- B树 B树每个节点存储了索引及索引数据(比如物理地址),每个叶节点具有相同的深度,如果按照默认大概16K的页大小计算,互联网数据每行数据大概1K计算,每个节点可存16条数据。也就是意味着,我们如果要存储大量数据,则需要更高的树结构完成。同时,因为B树中,虽然节点中索引是从左到右按大小排序,但是节点之间不存在指针连接,意味着,如果需要查询某一个范围中的数据,一旦一个节点中的数据读取完毕,进行下次查询时,仍然需要从头节点开始进行查找下一个节点所在的位置。也就是说对范围查询仍然无法得到更好支持。
- B+树 B+树是一种多路平衡查找树,每个节点可以存储多个关键字和数据,在B+树中,非叶子节点只存储关键字,而不存储数据,所以这就意味着,每个节点可以存储更多的索引数据及节点指针,同时所有子节点均冗余了索引所在数据行,这就意味着,较低的高度,就可以存储客观的数据。比如,mysql inndb 索引页大小默认16K,非子节点一个索引和节点指针占用大概8+6个字节,那么每个非叶子节点,大概可以存储1170个索引数据,若是树高为3,那么就可以存储1170* 1170*16(子节点每个数据大概占用1k,所以仅可以存储16个数据行),约2千万条数据轻松完成存储。同时,B+树的叶子节点构成一个有序链表,叶子节点间存有相互指针,支持高效的区间查询操作。
所以,综合以上说明,MYSQL使用B+树结构做数据索引的原因:
-
B+树是多路平衡查找树,每个节点可以存储多个关键字和数据,因此可以减少节点数,从而减少磁盘I/O次数,提高检索效率。相比之下,二叉树、红黑树的节点只能存储一个关键字和数据,需要更多的节点来存储相同的数据量。节点的增多势必会增加I/o操作,降低效率。
-
B+树具有很好的顺序性,可以提高区间查找的效率。由于B+树的叶子节点构成一个有序链表,因此在执行范围查询时,只需要遍历有序链表,而不需要进行全表扫描,从而提高查询效率。很显然Hash 无法支持范围查找,而B树在范围查找时,因为叶子节点之间没有相互之间的指针,无法知道彼此地址,在一个节点完成查询后,必须再次从根节点进行I/O定位查询下一个范围节点。
-
B+树可以减少索引更新的代价。由于B+树的非叶子节点只存储关键字,而不存储数据,因此在更新索引时,只需要更新叶子节点,而不需要更新非叶子节点,这可以减少索引更新的代价。
-
B+树对于大型数据集的存储和查询效率更高。由于B+树具有良好的平衡性和顺序性,因此在存储和查询大型数据集时,B+树的效率更高,能够更好地应对大规模数据的存储和查询需求。
总之,数据库使用B+树做索引是为了提高检索效率、支持高效的区间查询、减少索引更新代价以及更好地应对大规模数据的存储和查询需求。
以上学习拙见,如有错误,敬请指正。