1. 一个简单的索引设计方案

      (1)下一个数据页中用户记录的主键值必须大于上一个页中用户记录的主键值。
      (2)给所有的页建立一个目录项。
      image.png
      key:为页记录中最小主键,page_no:页地址
      例如找主键值为20,使用二分法快速定位它在目录项3中(12<20<209),再根据页的地址找到页,再使用二分法查找。

    2. 迭代1次:目录项记录的页

    image.png
    innoDB如何区分一条记录是普通的用户记录还是目录项记录还是目录项记录呢?
    image.png
    record_type:0:普通的用户记录
    1:目录项记录
    2:最小记录
    3:最大记录

    1. 迭代2次:多个目录项记录的页

    image.png
    随着数据页的增加,目录页装不下了,创建新的目录页。
    会出现坏情况:直到最后一个目录页或者直到接近最后的才找到那么就会多很多次IO。

    1. 迭代3次:目录项记录页的目录页

    image.png
    生成一个更高级的目录,就像一个多级目录一样,大目录里嵌套小目录。又可以二分了,减少IO次数。层数越低,IO次数就越少。所以用到的B+树都不会超过4层。

    1. 常见索引概念

    索引按照物理实现方式,索引可以分为 2 种:聚簇(聚集)和非聚簇(非聚集)索引。也把非聚集索引称为二级索引或者辅助索引。
    (1):聚簇索引
    特点:
    1. 使用记录主键值的大小进行记录和页的排序,这包括三个方面的含义:
    页内的记录是按照主键的大小顺序排成一个单向链表。
    各个存放用户记录的页也是根据页中用户记录的主键大小顺序排成一个双向链表。
    存放目录项记录的页分为不同的层次,在同一层次中的页也是根据页中目录项记录的主键大小顺序排成一个双向链表。
    2. B+树的叶子节点存储的是完整的用户记录。
    所谓完整的用户记录,就是指这个记录中存储了所有列的值(包括隐藏列)。
    优点:
    数据访问更快,因为聚簇索引将索引和数据保存在同一个B+树中,因此从聚簇索引中获取数据比非聚簇索引更快。
    聚簇索引对于主键的排序查找和范围查找速度非常快按照聚簇索引排列顺序,查询显示一定范围数据的时候,由于数据都是紧密相连,数据库不用从多个数据块中提取数据,所以节省了大量的io操作。
    缺点:
    插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重影响性能。因此,对于InnoDB表,我们一般都会定义一个自增的ID列为主键。
    更新主键的代价很高,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般定义主键为不可更新。
    (2)二级索引(辅助索引、非聚簇索引)
    image.png
    概念:回表 我们根据这个以c2列大小排序的B+树只能确定我们要查找记录的主键值也就是有c1,c2但没有c3,所以想根据c2列的值查找到完整的用户记录的话,仍然需要拿着c1主键值到 聚簇索引 中再查一遍,这个过程称为 回表 。也就是根据c2列的值查询一条完整的用户记录需要使用到 2 棵B+树!
    问题:为什么我们还需要一次 回表 操作呢?直接把完整的用户记录放到叶子节点不OK吗?
    因为如果每个二级索引叶子节点全部都放了,那就会冗余。只要在聚簇索引中才存放。
    小结:聚簇索引与非聚簇索引的原理不同,在使用上也有一些区别
    1)聚簇索引的叶子节点存储的是数据记录,非聚簇索引的叶子节点存储的是数据位置(也就是主键拿来回表)。非聚簇索引不会影响数据表的物理存储顺序。
    2)一个表只能有一个聚簇索引,因为只能有一种排序存储的方式,但可以有多个非聚簇索引,也就是多个索引目录提供数据检索。
    3)使用聚簇索引的时候,数据的查询效率高,但如果对数据进行插入、删除、更新等操作,效率会比非聚簇索引低。因为这些操作并不会影响非聚簇索引。
    (3)联合索引
    image.png
    各条记录先按照c2列的值进行排序,如果记录的c2列相同,则按照c3列的值进行排序。

    1. InnoDB的B+树索引的注意事项

      1. 1)根页面位置万年不动,会一直升级。数据页→目录页→上层目录...<br />2)内节点中目录项记录的唯一性。非叶子节点记录除了页号要唯一,不然添加查询等操作会有问题。<br />3)一个页面最少要存储两条记录。