聚簇索引和非聚簇索引

原文:https://blog.csdn.net/lm1060891265/article/details/81482136

聚簇索引并不是一种单独的索引类型,而是一种数据存储方式。具体细节依赖于其实现方式。

MySQL 数据库中 InnoDB 存储引擎,B+ 树索引可以分为聚簇索引(也称聚集索引,clustered index)和辅助索引(有时也称非聚簇索引或二级索引,secondary index,non-clustered index)。这两种索引内部都是 B+ 树,聚集索引的叶子节点存放着一整行的数据。

InnoDB 中的主键索引是一种聚簇索引,非聚簇索引都是辅助索引,像复合索引、前缀索引、唯一索引。

InnoDB 使用的是聚簇索引,MyISAM 使用的是非聚簇索引。

聚簇索引(聚集索引)

聚簇索引就是按照每张表的主键构造一颗 B+ 树,同时叶子节点中存放的就是整张表的行记录数据,也将聚集索引的叶子节点称为数据页。这个特性决定了表中数据也是索引的一部分,每张表只能拥有一个聚簇索引。

InnoDB 通过主键聚集数据,如果没有定义主键,InnoDB 会选择非空的唯一索引代替。如果没有这样的索引,InnoDB 会隐式的定义一个主键来作为聚簇索引。

聚簇索引的优缺点

优点:

  1. 数据访问更快,因为聚簇索引将索引和数据保存在同一个 B+ 树中,因此从聚簇索引中获取数据比非聚簇索引更快。

  2. 聚簇索引对于主键的排序查找和范围查找速度非常快。

缺点:

  1. 插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重影响性能。因此,对于 InnoDB 表,我们一般都会定义一个自增的 ID 列为主键。

  2. 更新主键的代价很高,因为将会导致被更新的行移动。因此,对于 InnoDB 表,我们一般定义主键为不可更新。

  3. 二级索引访问需要两次索引查找,第一次找到主键值,第二次根据主键值找到行数据。

辅助索引(非聚簇索引)

聚簇索引之上创建的索引称之为辅助索引,辅助索引访问数据总是需要二次查找。辅助索引叶子节点存储的不再是行的物理位置,而是主键值。通过辅助索引首先找到的是主键值,再通过主键值找到数据行的数据页,再通过数据页中的 Page Directory 找到数据行。

InnoDB 辅助索引的叶子节点并不包含行记录的全部数据,叶子节点除了包含键值外,还包含了相应行数据的聚簇索引键。

辅助索引的存在不影响数据在聚簇索引中的组织,所以一张表可以有多个辅助索引。在 InnoDB 中有时也称辅助索引为二级索引。

InnoDB 聚簇索引和 MyISAM 非聚簇索引的比较说明
img

参考:https://www.cnblogs.com/zlcxbb/p/5757245.html

InnoDB 索引实现

InnoDB 也使用 B+Tree 作为索引结构,但具体实现方式却与 MyISAM 截然不同。

1)主键索引

MyISAM 索引文件和数据文件是分离的索引文件仅保存数据记录的地址。而在 InnoDB 中,表数据文件本身就是按 B+Tree 组织的一个索引结构,这棵树的叶节点 data 域保存了完整的数据记录。这个索引的 key 是数据表的主键,因此 InnoDB 表数据文件本身就是主索引。

img

上图是 InnoDB 主索引(同时也是数据文件)的示意图,可以看到叶节点包含了完整的数据记录。这种索引叫做聚集索引。因为 InnoDB 的数据文件本身要按主键聚集,所以 InnoDB 要求表必须有主键(MyISAM 可以没有),如果没有显式指定,则 MySQL 系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则 MySQL 自动为 InnoDB 表生成一个隐含字段作为主键,这个字段长度为 6 个字节,类型为长整形

2)InnoDB 的辅助索引

InnoDB 的所有辅助索引都引用主键作为 data 域。例如,下图为定义在 Col3 上的一个辅助索引:

img

InnoDB 表是基于聚簇索引建立的。因此 InnoDB 的索引能提供一种非常快速的主键查找性能。不过,它的辅助索引(Secondary Index,也就是非主键索引)也会包含主键列,所以,如果主键定义的比较大,其他索引也将很大。如果想在表上定义很多索引,则争取尽量把主键定义得小一些。InnoDB 不会压缩索引。

以字符的 ASCII 码作为比较准则。聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。

不同存储引擎的索引实现方式对于正确使用和优化索引都非常有帮助,例如知道了 InnoDB 的索引实现后,就很容易明白:

  1. 为什么不建议使用过长的字段作为主键,因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。

  2. 用非单调的字段作为主键在 InnoDB 中不是个好主意,因为 InnoDB 数据文件本身是一颗 B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持 B+Tree 的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。

InnoDB 使用的是聚簇索引,将主键组织到一棵 B+ 树中,而行数据就储存在叶子节点上,若使用where id = 14这样的条件查找主键,则按照 B+ 树的检索算法即可查找到对应的叶节点,之后获得行数据。若对 Name 列进行条件搜索,则需要两个步骤:第一步在辅助索引 B+ 树中检索 Name,到达其叶子节点获取对应的主键。第二步使用主键在主索引 B+ 树种再执行一次 B+ 树检索操作,最终到达叶子节点即可获取整行数据。

MyISAM 索引实现

MyISAM 索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。

1)主键索引(Primary key)

MyISAM 引擎使用 B+Tree 作为索引结构,叶节点的 data 域存放的是数据记录的地址。下图是 MyISAM 主键索引的原理图:

img

这里设表一共有三列,假设我们以 Col1 为主键,可以看出 MyISAM 的索引文件仅仅保存数据记录的地址。

2)辅助索引(Secondary key)

在 MyISAM 中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求 key 是唯一的,而辅助索引的 key 可以重复。如果我们在 Col2 上建立一个辅助索引,则此索引的结构如下图所示:

img

同样也是一颗 B+Tree,data 域保存数据记录的地址。因此,MyISAM 中索引检索的算法为首先按照 B+Tree 搜索算法搜索索引,如果指定的 Key 存在,则取出其 data 域的值,然后以 data 域的值为地址,读取相应数据记录。

MyISAM 的索引方式也叫做“非聚集”的,之所以这么称呼是为了与 InnoDB 的聚集索引区分。

MyISM 使用的是非聚簇索引,非聚簇索引的两棵 B+ 树看上去没什么不同,节点的结构完全一致只是存储的内容不同而已,主键索引 B+ 树的节点存储了主键,辅助键索引 B+ 树存储了辅助键。表数据存储在独立的地方,这两颗 B+ 树的叶子节点都使用一个地址指向真正的表数据,对于表数据来说,这两个键没有任何差别。由于索引树是独立的,通过辅助键检索无需访问主键的索引树。

为了更形象说明这两种索引的区别,我们假想一个表如下图存储了 4 行数据。其中 Id 作为主索引,Name 作为辅助索引。图示清晰的显示了聚簇索引和非聚簇索引的差异。

img

问题:主键索引是聚集索引还是非聚集索引?

在 InnoDB 下主键索引是聚集索引,在 MyISAM 下主键索引是非聚集索引。

问题:聚簇索引和非聚簇索引的区别?

聚簇索引的叶子节点存放的是主键值和数据行,支持覆盖索引;二级索引的叶子节点存放的是主键值或指向数据行的指针。

由于节子节点(数据页)只能按照一颗 B+ 树排序,故一张表只能有一个聚簇索引。辅助索引的存在不影响聚簇索引中数据的组织,所以一张表可以有多个辅助索引。

注:覆盖索引(covering index)指一个查询语句的执行只用从索引中就能够取得,不必从数据表中读取。也可以称之为实现了索引覆盖。当一条查询语句符合覆盖索引条件时,MySQL 只需要通过索引就可以返回查询所需要的数据,这样避免了查到索引后再返回表操作,减少 I/O 提高效率。如,表 covering_index_sample 中有一个普通索引 idx_key1_key2(key1,key2)。当我们通过 SQL 语句:select key2 from covering_index_sample where key1 = 'keyTest'; 的时候,就可以通过覆盖索引查询,无需回表。

参考:http://www.admin10000.com/document/5372.html

posted @ 2024-06-28 15:44  Higurashi-kagome  阅读(2)  评论(0编辑  收藏  举报