Mysql聚簇索引 二级索引 辅助索引

时间:2022-02-15 05:24:58

Mysql聚簇索引 二级索引 辅助索引

索引就像是书的目录,是与表或视图关联的磁盘上结构,可以加快从表或视图中检索行的速度。索引中包含由表或视图中的一列或多列生成的键。这些键存储在一个结构(BTree)中,使SQL可以快速有效地查找与键值关联的行。

为什么要建索引,即索引的优点

  1. 没有索引则检索过程变成了顺序查找,O(n)的时间复杂度几乎是不能忍受的。
  2. 建立索引的列可以保证行的唯一性,生成唯一的rowId
  3. 建立索引可以有效缩短数据的检索时间
  4. 建立索引可以加快表与表之间的连接
  5. 为用来排序或者是分组的字段添加索引可以加快分组和排序顺序

索引的缺点

  1. 创建索引和维护索引需要时间成本,这个成本随着数据量的增加而加大
  2. 创建索引和维护索引需要空间成本,每一条索引都要占据数据库的物理存储空间,数据量越大,占用空间也越大(数据表占据的是数据库的数据空间)
  3. 降低表的增删改的效率,因为每次增删改索引需要进行动态维护,导致时间变长

什么样的表和列要建立索引

①  总的来说就是数据量大的,经常进行查询操作的表要建立索引

②  表中字段建立索引应该遵循几个原则:

  1)   越小的数据类型通常更好:越小的数据类型通常在磁盘、内存中都需要更少的空间,处理起来更快。

  2)   简单的数据类型更好:整型数据比起字符,处理开销更小,因为字符串的比较更复杂,处理起来也更耗时。

  3)   尽量避免NULL:应该指定列为NOT NULL。含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值。

  4)   对非唯一的字段,例如“性别”这种大量重复值的字段,增加索引也没有什么意义,所以索引的建立应当更多的选取唯一性更高的字段

③  表与表连接用于多表联合查询的约束条件的字段应当建立索引

④  用于排序的字段可以添加索引,用于分组的字段应当视情况看是否需要添加索引。

⑤  添加多列索引的时候,对应的多条件查询可以触发该索引的同时,索引最左侧的列的单条件查询也可以触发

⑥  如果有些表注定只会进行查询所有,也就没必要添加索引,因为查询全部只能进行全量搜索即扫描全表。

 

聚簇索引和非聚簇索引

MySQL普遍使用B Tree实现其索引结构。

mysql中每个表都有一个聚簇索引(clustered index ),除此之外的表上的每个非聚簇索引都是二级索引,又叫辅助索引(secondary indexes)。

当数据库一条记录里包含多个字段时,一棵B 树就只能存储主键,如果检索的是非主键字段,则主键索引失去作用,又变成顺序查找了。这时应该在第二个要检索的列上建立第二套索引。  这个索引由独立的B 树来组织。有两种常见的方法可以解决多个B 树访问同一套表数据的问题,一种叫做聚簇索引(clustered index ),一种叫做非聚簇索引(secondary index)。这两个名字虽然都叫做索引,但这并不是一种单独的索引类型,而是一种数据存储方式。对于聚簇索引存储来说,行数据和主键B 树存储在一起,辅助键B 树只存储辅助键和主键,主键和非主键B 树几乎是两种类型的树。对于非聚簇索引存储来说,主键B 树在叶子节点存储指向真正数据行的指针,而非主键。

聚簇索引并不是一种单独的索引类型,而是一种数据存储方式。具体的细节依赖于其实现方式,但InnoDB的聚簇索引实际上在同一个结构中保存了B-Tree索引和数据行。

当表有聚簇索引时,他的数据行实际上存放在索引的叶子页(leaf page)中。术语 “聚簇”表示数据行和相邻的键值紧凑地存储在一起(这并非总成立)。

因为无法同时把数据行存放在两个不同的地方,索引一个表只能有一个聚簇索引。

 

Mysql聚簇索引 二级索引 辅助索引

注:叶子页面包含完整的元组,而内节点页面仅包含索引的列(索引的列为整型)。一些DBMS允许用户指定聚簇索引,但是MySQL的存储引擎到目前为止都不支持。InnoDB对主键建立聚簇索引。如果你不指定主键,InnoDB会用一个具有唯一且非空值的索引来代替。如果不存在这样的索引,InnoDB会定义一个隐藏的主键,然后对其建立聚簇索引。一般来说,DBMS都会以聚簇索引的形式来存储实际的数据,它是其它二级索引的基础。

 innodb MyISAM

以InnoDB来说,每个InnoDB表具有一个特殊的索引称为聚集索引。如果您的表上定义有主键,该主键索引是聚集索引。如果你不定义为您的表的主键时,MySQL取第一个唯一索引(unique)而且只含非空列(NOT NULL)作为主键,InnoDB使用它作为聚集索引。如果没有这样的列,InnoDB就自己产生一个这样的ID值,它有六个字节,而且是隐藏的,使其作为聚簇索引。

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

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

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

Mysql聚簇索引 二级索引 辅助索引

Mysql聚簇索引 二级索引 辅助索引

 

  我们重点关注聚簇索引,看上去聚簇索引的效率明显要低于非聚簇索引,因为每次使用辅助索引检索都要经过两次B 树查找,这不是多此一举吗?聚簇索引的优势在哪?

  1 由于行数据和叶子节点存储在一起,这样主键和行数据是一起被载入内存的,找到叶子节点就可以立刻将行数据返回了,如果按照主键Id来组织数据,获得数据更快。

  2 辅助索引使用主键作为"指针" 而不是使用地址值作为指针的好处是,减少了当出现行移动或者数据页分裂时辅助索引的维护工作,使用主键值当作指针会让辅助索引占用更多的空间,换来的好处是InnoDB在移动行时无须更新辅助索引中的这个"指针"。也就是说行的位置(实现中通过16K的Page来定位,后面会涉及)会随着数据库里数据的修改而发生变化(前面的B 树节点分裂以及Page的分裂),使用聚簇索引就可以保证不管这个主键B 树的节点如何变化,辅助索引树都不受影响。

 

 

参考文章:

https://www.cnblogs.com/wajika/p/6682460.html

https://www.cnblogs.com/williamjie/p/11081081.html

https://www.cnblogs.com/ytc6/p/9370962.html