MySQL的聚簇索引和覆盖索引
2020-10-24 本文已影响0人
雁阵惊寒_zhn
聚簇索引
聚簇索引不是一种单独的索引类型,而是一种数据存储方式。InnoDB聚簇索引的数据行实际上存放在索引的叶子页(leaf page)中。“聚簇”代表着数据行和相邻的键值紧凑地存储在一起,InnoDB通过主键聚集数据,如果不存在主键,InnoDB会选择唯一的非空索引,如果也没有唯一非空索引,InnoDB隐式定义一个主键来作为聚簇索引。一张表中只能存在一个聚簇索引。
聚簇索引优点
- 可以把相关数据保存在一起。
- 数据访问速度更快。索引和数据保存在同一棵B+Tree中,因此从聚簇索引获取数据更快些。
- 使用覆盖索引扫描的查询可以直接使用叶节点中的主键值。
- 聚簇索引最大限度提升了IO密集型应用的性能。
聚簇索引缺点
- 插入速度严重依赖插入顺序。
- 更新聚簇索引代价高。
- 聚簇索引可能引起页分裂(page split),页分裂会导致表占用更多的磁盘空间。
- 聚簇索引可能导致全表扫描变慢,尤其是行稀疏,或者页分裂导致数据存储不连续的时候。
- 二级索引(非聚簇索引)可能比想象的要更大,因为在二级索引的叶子节点包含了引用行的主键列。
- 二级索引访问需要两次索引查找,而不是一次。二级索引叶子节点保存的不是指向行的物理位置的指针,而是行的主键值。
InnoDB聚簇索引的存储
InnoDB中聚簇索引“就是”表。聚簇索引的每一个叶子节点都包含了主键值、事务ID、用于事务和MVCC的回滚指针以及所有剩余的列。InnoDB二级索引的叶子节点中存储的不是行指针,而是主键值。这样的设计减少了行移动或者页分裂时二级索引的维护成本,但是在二级索引访问时却需要两次索引查找。
InnoDB聚簇索引尽可能地按主键顺序插入数据,并且尽可能地使用单调增加的聚簇键的值来插入新行。
InnoDB聚簇索引的存储如下图所示:
截图自《高性能MySQL(第三版)》
覆盖索引
如果一个索引包含(覆盖)所有需要查询的字段值,我们就称之为“覆盖索引”。
下面的情况适合使用覆盖索引,查询时只扫描覆盖索引,而不需回表查询。
- 索引条目通常远小于数据行大小,只读取索引,会减少访问量。
- 索引按照列值顺序存储,对于范围查询效率更高。
- InnoDB二级索引如果能够覆盖索引,可以避免对主键索引的二次查询。
- 若索引缓存在内存中,查询时开销更小。
关于索引可能的面试题
问题一:MySQL的底层数据结构
MyISAM引擎索引文件和数据文件是分离的,InnoDB引擎索引数据文件本身就是索引文件(聚簇索引)。
问题二:为什么InnoDB表必须有主键,并且推荐使用整型的自增主键
InnoDB通过主键聚集数据,如果不存在主键,InnoDB会选择唯一的非空索引,如果也没有唯一非空索引,InnoDB隐式定义一个主键来作为聚簇索引。
自增主键可以保证数据顺序增加,如果不是顺序增加,会引起B+Tree叶子节点因为插入导致的数据检索,页分裂和保持顺序等消耗,而顺序增加只需要在B+Tree最后叶子节点加入就可以了。
问题三:为什么非主键索引结构叶子节点存储的是主键值
这样的设计减少了行移动或者页分裂时二级索引的维护成本,但是在二级索引访问时却需要两次索引查找。