MySQL --- 读书笔记 --- 索引(2)

为什么需要索引

数据库的数据不是连续存储在磁盘上的,假设查找数据的方式是逐条查询,那么最坏情况下,查询一个数据就需要一次磁盘I/O,那么消耗在I/O上的时间就会非常大。

那么如果我们为数据的存储建立一个索引表,就像是书本的目录一样,然后再使用二叉树这样的数据结构来查找数据,那么我们知道,二叉树的检索时间复杂度是对数级别的,也就是说,磁盘的I/O次数从线性级别减低到对数级别了,这样大大提高了检索速度

索引概述

  • 索引的本质,是一种有序的数据结构,可以满足特定的查找算法,然后以某种方式指向真实数据
  • 索引是在存储引擎中实现的,所以不同的存储引擎可能有不一样的索引结构

索引的优点

  • 降低磁盘I/O次数,提高检索效率
  • 天然有序,降低有序查询的时间
  • 对于有依赖关系的两张表,可以加速表之间的连接
  • 建立唯一索引,保证数据的唯一性

索引的缺点

  • 创建索引和维护索引需要耗费时间,随着数据量的增加,耗费时间也会增加
  • 索引也需要占用磁盘空间
  • 索引的建立可以提高查询速度,但是也会降低表更新的速度,对表的增、删、改,索引也会动态地维护,这就降低了数据的维护速度

聚簇索引

  • 聚簇索引指的是一种数据存储方式,所有的记录都存储在叶子结点,索引即数据,数据即索引
  • 数据页内的记录是按照主键大小顺序排成一个单向链表
  • 数据页之间也是按照页中记录主键大小顺序排成一个双向链表
优点
  • 数据访问快,聚簇索引将数据和索引保存在同一个B+树中,因此这样获取数据更快
  • 聚簇索引对于主键的排序查找和范围查找更快
  • 相邻数据是紧密联系的,所以在范围获取数据时,会减少I/O次数
缺点
  • 插入速度依赖插入顺序,按照主键的顺序插入数据是最快的,否则会出现页分裂,影响性能
  • 更新主键的代价很高,一般不允许主键的更新
  • 二级索引的访问需要两次索引查找,一次找到主键,一次根据主键找到记录

二级索引

  • 以其他列的数据,建立另一个B+树,叶子结点的内容不带有全部数据,只有列的数据以及对应的主键值

联合索引

  • 以多个列数据作为排序规则,建立一个B+树,它首先会按照第一个列的顺序排列,当第一个列出现相同数据时,按照第二个列的顺序排列,以此类推;最后叶子结点也是只有列的值以及对应的主键

B+树索引的注意事项

  1. 根页面位置万年不动
  • 每当为某个表创建一个索引时,都会为这个索引创建一个根节点页面,最开始没有数据的时候,根节点中没有记录也没有目录项
  • 当开始向表中插入记录时,会先把记录存储在根节点中
  • 当根节点中的空间用完之后,此时会将根节点中的数据复制到一个新的页中,然后对这个页进行页分裂,得到一个新页,此时新记录会放在两个新的页中,然后根节点就会升级为只存储目录项的页
  • 然后在根节点中的目录项记录满了之后,重复上面的操作,但是根节点依旧不动摇
  1. 内节点中目录项记录的唯一性
  • 当二级索引中的列都一样的时候,在插入一条新记录时,无法区分应该在哪个页中记录
  • 为了让新记录能够找到所在页,我们需要保证在B+树中的同一层节点的目录项记录除了页号以外是唯一的,所以在目录项中,除了有索引列和页号,还有主键
  1. 一个页最少存储2条记录

索引的代价

  • 空间的代价:每建立一个索引,都要为其建立一个B+树,每一个树结点都是一个数据页,每个数据页默认是16KB
  • 时间的代价:每次增删改,都需要对每个索引进行修改,那我们知道,每个索引树,无论是目录项层次或者叶子结点层次还是页结点内部的记录,都是按照索引列的大小排序的,那么经过增删改之后,节点的顺序会被破坏,那就需要额外的时间进行一些记录位移,页分裂,页面回收等操作来维护索引树;所以索引越多,增删改的性能就越差

不选择Hash索引的理由

  • Hash索引只能满足确定性的查找,例如(=),(!=),如果进行范围查找,会退化成全表检索,但是树的有序性,会保持查找的高效
  • Hash索引是无序的,在进行一些带有排序的查找时,需要二次排序
  • 联合索引下,Hash索引需要两个列联合才可以查找,没办法对一个或者几个列查找
  • 对于等值查找,Hash索引效率很高,但是当索引列有很多重复值时,Hash索引会遇到Hash冲突,那么查找会变得耗时
  • 相比之下,树结构的索引的适用性更加广
  • InnoDB本身不支持Hash索引,但是提供自适应Hash索引,对于某个经常被访问的数据,当满足一定条件时,会将这个数据页的地址放到Hash表中

B+树与B树的差异

  1. 有K个孩子就有K个关键字,B树有K个孩子,就有K-1个关键字
  2. 非叶子节点的关键字也会同时存在于子节点中,并且是子节点中所有关键字的最大或最小
  3. 非叶子节点仅仅用于索引,不保存数据,所有记录信息放在叶子节点,在B树中,非叶子节点也会保存记录信息
  4. 所有关键字都在叶子节点中出现,叶子节点构成一个有序的链表

B+树索引中间节点不存储数据有什么好处

  1. 查询效率更加稳定,因为需要获得数据,每次都必须访问到叶子节点才可以
  2. 查询效率更高,中间节点只存放索引信息,导致在相同页节点大小可以存放的目录信息更多,那就导致分叉越多,然后B+树的树高更小,磁盘I/O也就更少,速度也就更快
  3. 范围查询效率也更高,因为所有数据都在叶子节点,而叶子节点之间会有有序链表连接,那就可以用指针连接查找,速度更快

B+树的存储能力

InnoDB中的页大小是16KB,一般表的主键大小是4/8byte,一个指针一般是4/8byte,也就是说一个页中大概可以存储(16/(8+8)=1K)个记录。

假设树高是3,那么最终叶子节点是有1k * 1k * 1k = 10亿条记录(假如叶子节点也是存储1k个数据)

InnoDB在设计时将根节点常驻在内存中,那么每次查询,最终的磁盘I/O次数不会超过3次,因为树高一般不超过4层

posted @ 2022-05-22 14:37  huang1993  阅读(13)  评论(0编辑  收藏  举报