索引的类型

聚集索引和非聚集索引

聚集索引:索引和记录都保存在同一个结构中,“聚集”索引和记录紧密联系在一起。

InnoDB的每一张表都只会有一个聚集索引(主键索引),如果没有定义主键,InnoDB会选择一个唯一的非空索引代替,如果没有这样的索引,InnoDB会隐式定义一个主键来作为聚集索引。InnoDB的索引是基于B+树的,所以聚集索引的叶子节点包含行的全部记录信息,非叶子节点只包含了索引列和指向下一页的指针

非聚集索引(二级索引):叶子节点保存了主键值,要定位主键的行记录,需要在查找一遍主键索引。

InnoDB二级索引中的叶子节点中存储的行的信息,而是主键值,并以此主键值指向行的信息。非叶子节点存储的是索引列和指向下一页的指针。减少了当行出现移动或数据页分裂时二级索引的维护工作。使用主键值会让二级索引占用更多的内存空间(这就是为什么要让主键值尽可能的小,以占用更少的空间)。所以当使用二级索引查找行记录信心的时候,此时就需要进行两次索引查找,第一次根据二级索引找到主键值,然后第二次利用主键值找到行记录的全部信息。

覆盖索引:如果一个索引包含(或者说覆盖)所有需要查询的字段的值,我们就称之为“覆盖索引”。(就是索引已经有你想要的数据了,就不需要去查找行了)

聚集索引的优点:

1. 可以把相关数据保存在一起。如根据一个用户的id来聚集数据,这样只需要从磁盘读取少数的数据页就可以了。

2. 数据访问更快,聚集索引将数据和索引保存在同一个B+tree中,因此从聚集索引中获取数据通常比在非聚集索引中查找快。(一个一次,一个二次)

3. 使用覆盖索引扫描的查询可以直接使用叶节点中的主键值。

聚集索引的缺点:

1.插入速度严重依赖于插入顺序。按照主键的顺序插入式加载到InnoDB表中速度最快的方式。但如果不是按照主键的顺序插入加载数据,插入速度会受到影响。

2. 二级索引(非聚集索引)可能很大,因为二级索引的叶子节点包含了引用行的主键。

3. 更新聚集索引列的代价很高,因为会强制InnoDB将每个被更新的行移动到新的位置。

4.聚集索引可能会导致全表扫描变慢,尤其是行比较稀疏,或者由于页分裂操作导致数据存储不连续的时候。

5. 基于聚集索引的表在插入新行,或者主键被更新需要移动行的时候,可能会面临“页分裂”的问题,当行的主键值要求必须将这一行插入某个已满的页中时,存储引擎会将该页分裂成两个页面来容纳该行,这就是一次页分裂操作,页分裂会导致表占用更多的磁盘空间。

6. 二级索引需要两次索引查找,而不是一次。

为什么建议使用顺序主键,而不是随机的主键?

因为如果主键是顺序的话,InnoDB把每一条记录都存储在上一条记录的后面,当达到页的最大填充因子时(InnoDB默认的最大填充因子是页大小的15/16,留出部分空间用于以后修改),下一条记录就会写入新的页中,一旦数据按照这种顺序方式加载,主键页就会近似于被顺序的记录填满,这也是期望的结果。

而如果随机的话,因为新行的主键值不一定比之前插入的大,所以InnoDB无法简单地总是把新行插入到索引的最后,而是需要为新的行寻找合适的位置——一般是已有数据的中间位置,并且分配空间,这回导致做很多额外工作,并且导致数据不够优化。

1. 写入的目标页可能已经刷新到磁盘上并从缓存中删除,或者是还没有被加载到缓存中,InnoDB在插入之前不得不先找到并从磁盘读取目标页到内存中,这将导致大量的随机I/O。

2. 因为写入是乱序的,InnoDB不得不频繁地做页分裂操作,以便为新的行分配空间,页分裂会导致移动大量的数据。

3. 由于频繁的页分裂,页会变得稀疏并被不规则地填充,所以最终数据会有碎片。

顺序主键什么时候会导致更坏的结果?

对于高并发系统来说,在InnoDB中按主键顺序插入可能会造成明显的争用,主键的最后一个元素会成为争用点,因为所有的插入都发生在这里,所以并发插入可能会导致间隙锁竞争。

猜你喜欢

转载自blog.csdn.net/weixin_42294335/article/details/80456001
今日推荐