对MySQL底层索引深度解析( 二 )

  • 非叶子节点存的是key, 叶子节点存的是key和数据
  • 叶子节点指针相连,顺序查找速度更快
  • B 树和 B+树有什么不同呢?第一,B 树一个节点里存的是key和数据,而 B+树存储的是索引(地址),所以 B 树里一个节点存不了很多个数据,但是 B+树一个节点能存很多索引,B+树叶子节点存所有的数据 。
    第二,B+树的叶子节点是数据阶段用了一个链表串联起来,便于范围查找 。
    通过 B 树和 B+树的对比我们看出,B+树节点存储的是索引,在单个节点存储容量有限的情况下,单节点也能存储大量索引,使得整个 B+树高度降低,减少了磁盘 IO 。其次,B+树的叶子节点是真正数据存储的地方,叶子节点用了链表连接起来,这个链表本身就是有序的,在数据范围查找时,更具备效率 。因此 Mysql 的索引用的就是 B+树,B+树在查找效率、范围查找中都有着非常不错的性能 。
    综上所述mysql innodb 索引选择了B+树 。
    思考问题1、B+树叶子节点存的诗所有数据,如果1000万数据,那这个链表太大,不会影响性能吗?
    可以利用数据页,下面有重点分析
    2、InnoDB一棵B+树可以存放多少行数据?
    B+Tree 的根节点和枝节点中都不会存储数据,只有叶子节点才存储数据 。搜索 到关键字不会直接返回,会到最后一层的叶子节点 。比如我们搜索 id=3,虽然在第一 层直接命中了,但是全部的数据在叶子节点上面,所以我还要继续往下搜索,一直到叶 子节点 。
    举个例子:假设一条记录是 1K,一个叶子节点(一页)可以存储 16 条记录 。非叶 子节点可以存储多少个指针?
    假设索引字段是 bigint 类型,长度为 8 字节 。指针大小在 InnoDB 源码中设置为 6 字节,这样一共 14 字节 。非叶子节点(一页)可以存储 1024*16 / 14 = 1170 个这样的 单元(键值+指针),代表有 1170 个指针 。
    树深度为 2 的时候,有 1170^2 个叶子节点,可以存储的数据为:
    1170 * 1170 * 16 = 21902400 2000万
    在查找数据时一次页的查找代表一次 IO,也就是说,一张 2000 万左右的表,查询数据最多需要访问 3 次磁盘 。所以在 InnoDB 中 B+ 树深度一般为 1-3 层,它就能满足千万级的数据存储 。
    二、innodb的索引分析在 InnoDB 中,表都是根据主键顺序以索引的形式存放的,这种存储方式的表称为索引组织表 。
    上述中我们从不同维度分析了最终InnoDB 使用了 B+ 树索引模型,所以数据都是存储在 B+ 树中的 。
    每一个索引在 InnoDB 里面对应一棵 B+ 树 。假设,我们有一个主键列为 ID 的表,表中有字段 k,并且在 k 上有普通索引 。
    这个表的建表语句是:
    create table user(id int primary key,k int not null,name varchar(16),index (k))engine=InnoDB;表中 第一行到第五行 的 (ID,k) 值分别为 (100,1)、(200,2)、(300,3)、(500,5) 和 (600,6),两棵树的示例示意图如下 。
    对MySQL底层索引深度解析

    文章插图
     
    上图为:主健索引
    对MySQL底层索引深度解析

    文章插图
     
    上图为:普通索引
    根据上面的索引结构说明,我们来讨论一个问题:基于主键索引和普通索引的查询有什么区别?
    如果语句是 select * from T where ID=500,即主键查询方式,则只需要搜索 ID 这棵 B+ 树;
    如果语句是 select * from T where k=5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次 。这个过程称为回表 。也就是说,基于非主键索引的查询需要多扫描一棵索引树 。因此,我们在应用中应该尽量使用主键查询 。
    B+ 树为了维护索引有序性,在插入新值的时候需要做必要的维护 。以上面这个图为例,如果插入新的行 ID 值为 700,则只需要在 R5 的记录后面插入一个新记录 。如图
    对MySQL底层索引深度解析

    文章插图
     
    如果新插入的 ID 值为 400,就相对麻烦了,需要逻辑上挪动后面的数据,空出位置,如图 。
    对MySQL底层索引深度解析

    文章插图
     
    而更糟的情况是,如果 R5 所在的数据页已经满了,根据 B+ 树的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去 。这个过程称为页分裂 。在这种情况下,性能自然会受影响 。
    除了性能外,页分裂操作还影响数据页的利用率 。原本放在一个页的数据,现在分到两个页中,整体空间利用率降低大约 50% 。当然有分裂就有合并 。


    推荐阅读