Mysql的数据存储结构是怎样的

B+Tree,要理解什么是B+Tree,我们要从二叉树、平衡二叉树、红黑树说起。

在Mysql中,只有memory引擎使用了hash数据结构,而innodb使用的B+Tree。

二叉树

数据结构中重要的一种树形结构。树有高度,层数,路径,叶节点,根节点,父节点,左节点,右节点等基本概念除了叶子结点外每一个结点都有左右子结点的二叉树。树形数据结构可以利用二分查找快速查找。

平衡二叉树

二叉树的理想状态是越趋于平衡越好,树的深度越浅越好。在平衡二叉树中任意节点的左右两个子树的高度差的绝对值不超过1 ,因此在数据进行插入操作的时候,要操作若干个旋转来保持树的平衡,所以平衡二叉树的插入效率比较低,但是牺牲了插入效率提高了查找效率,尽管如此,但是数据多的时候,树的深度会越来越深,查询效率、插入效率会越来越低!

mysql从节点禁止写_数据

非平衡二叉树

举个例子,如果图中的树真的存在,就退化变成链表了。这种极端情况查找叶子节点J就不妙了。这样就没有办法发挥二分查找法的优势了。

mysql从节点禁止写_子节点_02

红黑树

红黑树是特殊的二叉查找树。在每个节点上有存储位表示节点的颜色,红(Red)或黑(Black),在红黑树中确保没有一条路径会比其他路径长出俩倍。所以,红黑树是接近平衡的二叉树。在红黑树中根节点是黑色的,叶子节点也是黑色,红色的节点下的子节点必须是黑色节点,这保证了从个任一节点到子节点或孙节点的路径中有相同数目的黑色节点数量。

红黑树被广泛使用,例如Java中的TreeSet、TreeMap。

mysql从节点禁止写_mysql_03

B树

这种数据结构的每个节点可以包含多个key值,同时呢也包含了多个分支。这样的设计是为了防止树的深度增加,这也是为什么B树比前面几种树的数据结构在查询的时候速度要快,性能高,时间短。在B树种还有一个概念就是degree,这个概念实际用来表示每个节点可以存储的子节点数量,degree=N-1,在Mysql中B树的存储结构,每个节点中需要保存主键key、数据data、子节点存储地址point。因为每个节点需要保存数据,数据data比较大的情况下会导致节点存储的主键key变少,树的宽度就会变窄,从而增加树的深度。

mysql从节点禁止写_mysql_04

InnoDB的默认情况一次读取磁盘块3个,每个磁盘块为16kb。在这个16kb中即包括主键key、也包含数据data,同时还要分配空间存储子节点point地址。假设一条数据以1kb计算,那么一个磁盘块绝对存储不下16条数据。我们不妨假设一下,一个节点存储10条数据,用10kb空间,剩余6kb,保存了10个子节点point地址。按照这样计算三层B树所 能保存的数据量

10的3次方=1000条数据。

B+Tree

mysql中很多场景和应用实际数据量一般都单表都能按万为单位,几十万,几百万的数据量如果使用B树,树的深度会非常大,通过让每个节点能够保存尽量多的子节点,让树横向扩展宽度,就能减少树的纵向深度。通过上面的图我们不难理解B+Tree的设计,B+Tree的非叶子节点,不再存储数据data,这让B+Tree极大增加了树的宽度,能够存储尽可能多的子节点,问题是数据如何存储呢,在B+Tree中数据保存在叶子节点上,最末级节点,并且是key-data关系保存(主键-数据)。

同样一个磁盘块16kb,在B+tree中一个节点只保存主键key-子节点存储指针point所占用的空间却小到按 字节计算。这是极大的横向宽展,为了说明这一点,方便计算,我们假设一对key-point占用空间16字节,那么一个节点将保存 16kb / 16byte = 1000个子节点,同样的树深度为3层,对比B树,在存储的数量 级别上B+Tre占据绝对优势。

1000的三次方=10亿

所以B+Tree与B tree完全不是一个数量级的。

mysql从节点禁止写_mysql_05

InnoDB B+Tree 的叶子节点

    在Mysql innoDB中数据和索引是保存在一起的,上图中所展示的不够全面。确切的是叶子节点中保存了key、数据data、索引。

    key 不一定是主键,但按照优先顺序,首先是主键作为key,如果表中没有主键,Mysql会从表中寻找唯一键作为key,如果既没有主键也没有唯一键,myslq会自动生成一个row_id作为key。

    当表中存在多个索引的时候,或者说创建索引的字段不是主键字段。在叶子节点中存储的data的内容是主键,而不是数据。

        只有当表中只存在一个主键索引的时候,叶子节点中的data的内容才是真正的数据。

 回表

        通过上面对叶子节点的张开,我们能够知道,非主键索引的叶子节点中data保存的是主键的值,当查询是通过非主键索引进行扫描的时候,先通过非主键索引的叶子节点获取data,就是主键的值,然后再根据主键的值进行第二次查询。这个过程叫做回表。

        实际在Mysql优化的时候,要尽量避免回表,也就要求要尽可能使用主键索引,减少或避免使用非主键索引。

索引覆盖

        索引覆盖实际是无需进行回表操作,简单说,就是通过非主键索引查询的字段与非主键索引相同,或索引中的数据满足查询,而不用再通过id去查询第二次。

        应当尽可能多的使用索引覆盖。