聚集索引和非聚集索引的区别底层_数据库-索引相关

一、什么是索引

在数据库中,索引的含义与日常意义上的“索引”一词并无多大区别(想想小时候查字典),它是用于提高数据库表数据访问速度的数据库对象。

总而言之,索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址,在数据十分庞大的时候,索引可以大大加快查询的速度,这是因为使用索引后可以不用扫描全表来定位某行的数据,而是先通过索引表找到该行数据对应的物理地址然后访问相应的数据

  • 索引可以避免全表扫描。多数查询可以仅扫描少量索引页及数据页,而不是遍历所有数据页。
  • 对于非聚集索引,有些查询甚至可以不访问数据页
  • 聚集索引可以避免数据插入操作集中于表的最后一个数据页
  • 一些情况下,索引还可用于避免排序操作

当然,众所周知,虽然索引可以提高查询速度,但是它们也会导致数据库系统「更新数据」的性能下降,因为大部分数据更新需要同时更新索引。

二、索引的适用场景

什么样的字段适合创建索引?

1、表的主键、外键一般必须有索引
2、数据量超过300的表应该有索引(不知道是什么依据,难道是经验之谈?)
3、经常与其他表进行连接的表,在连接字段上应该建立索引
4、经常出现在where子句中的字段,加快判断速度,特别是大表的字段,应该建立索引
5、经常用于排序的列上
6、经常用在范围内搜索的列上创建索引

什么场景不适合创建索引?

1、对于那些在查询中很少使用的列
2、对于那些只有取值种类较少的列也不应该增加索引,例如性别
3、对于那些定义为text、image和bit数据类型的列不应该增加索引。
这些列的数据量要么相当大,要么取值很少。
4、当修改性能远远大于检索性能时,不应该创建索引。修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因 此,当修改性能远远大于检索性能时,不应该创建索引。
5、不会出现在where条件中的字段不该建立索引

三、索引的分类

1、从存储结构上来划分:

BTree索引(B-Tree或B+Tree索引),Hash索引,full-index全文索引
这里的存储结构是指索引的组织形式,比如B+Tree索引,就是将索引页当做一个一个节点,然后以B+树的形式组织起来

2、从应用层次来分:

普通索引:即一个索引只包含单个列,一个表可以有多个单列索引
唯一索引:索引列的值必须唯一,但允许有空值
复合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并

3、根据中数据的物理顺序与键值的逻辑(索引)顺序关系:

聚集索引:并不是一种单独的索引类型,而是一种数据存储方式。
非聚集索引:不是聚簇索引,就是非聚簇索引,或者叫辅助索引

聚集索引和非聚集索引的差别,下面会有更加详细的说明。

四、索引的数据结构

一条索引记录中包含的基本信息包括:键值(即你定义索引时指定的所有字段的值)+逻辑指针(指向数据页或者另一索引页)

00018c5ba10d7b3b3089d85986ee61f2.png

通常状况下,由于索引记录仅包含索引字段值以及4-9字节的指针,索引实体比真实的数据行要小许多,索引页相较数据页来说要密集许多。一个索引页可以存储数量更多的索引记录,这意味着在索引中查找时在I/O上占很大的优势,理解这一点有助于从本质上了解使用索引的优势。

四、InnoDB中索引的实现

MySQL默认存储引擎InnoDB支持常见的几种索引:

  • B+树索引
  • 全文索引
  • 哈希索引

其中,对于频繁访问的表,InnoDB会自动的生成哈希索引,不能认为干预是否在一张表中生成哈希索引

五、InnoDB的B+树索引

数据库的B+树索引分为聚集索引和辅助索引或者叫非聚集索引。二者不同的地方是叶子节点存放的是否是一整行的信息。

聚集索引

表数据按照索引的顺序来存储的。
对于聚集索引,叶子结点即存储了真实的数据行,不再有另外单独的数据页。
当定义下来数据的逻辑顺序时,聚集索引能够比较快速的访问针对范围值的查询非聚集索引

非聚集索引

表数据存储顺序与索引顺序无关。对于非聚集索引,叶结点包含索引字段值及指向数据页数据行的逻辑指针,该层紧邻数据页,其行数量与数据表行数据量一致。

在一张表上只能创建一个聚集索引,因为真实数据的物理顺序只可能是一种。

5.1、聚集索引

在聚集索引中,叶结点也称为数据结点数据页,所有数据行的存储顺序与索引的存储顺序一致。

6166c74e48a739a02dfcc93e262b5f58.png

如上图,我们在名字字段上建立聚集索引,当需要在根据此字段查找特定的记录时,数据库系统会根据特定的系统表查找的此索引的根,然后根据指针查找下一个,直到找到。例如我们要查询“Green”,由于它介于[Bennet,Karsen],据此我们找到了索引页1007,在该页中“Green”介于[Greane, Hunter]间,据此我们找到叶结点1133(也即数据结点),并最终在此页中找以了目标数据行。

此次查询的IO包括3个索引页的查询(其中最后一次实际上是在数据页中查询)。这里的查找可能是从磁盘读取(Physical Read)或是从缓存中读取(Logical Read),如果此表访问频率较高,那么索引树中较高层的索引很可能在缓存中被找到。所以真正的IO可能小于上面的情况。

5.2、非聚集索引

非InnoDB实现:

非聚集索引与聚集索引相比:

  • 叶子结点并非数据结点
  • 叶子结点为每一真正的数据行存储一个“键-指针”对
  • 叶子结点中还存储了一个指针偏移量,根据页指针及指针偏移量可以定位到具体的数据行。
  • 类似的,在除叶结点外的其它索引结点,存储的也是类似的内容,只不过它是指向下一级的索引页的。

聚集索引是一种稀疏索引,数据页上一级的索引页存储的是页指针,而不是行指针。

而对于非聚集索引,则是密集索引,在数据页的上一级索引页它为每一个数据行存储一条索引记录。

对于根与中间级的索引记录,它的结构包括:

  • 索引字段值
  • RowId(即对应数据页的页指针+指针偏移量)。在高层的索引页中包含RowId是为了当索引允许重复值时,当更改数据时精确定位数据行。
  • 下一级索引页的指针

对于叶子层的索引对象,它的结构包括:

  • 索引字段值
  • RowId

8ec29ce9b1262e41d2faf696eb4b1c3a.png

针对上图,如果我们同样查找“Green”,那么一次查询操作将包含以下IO: 3个索引页的读取+1个数据页的读取。同样,由于缓存的关系,真实的IO实际可能要小于上面列出的。

InnoDB实现:

在InnoDB中,非聚集索引的叶子节点并不包含行记录的全部信息,除了包含键值以外,还有包含了一个书签bookmark,本质上,bookmark就是相应行数据的「聚集索引键」

在进行查找时,本质上是从非主键->主键->行记录的查找过程

辅助索引的存在并不影的数据在聚集索引中的组织。因此每张表上可以有多个辅助索引。当通过辅助索引来查找数据时,InnoDB存储引擎会遍历辅助索引并通过叶节点的指针获得指向主键索引的主键,然后再通过主键索引来找到一个完整的行记录。

举例来说。如果在一一棵高度为3的辅助索引树中查找数据,那需要对这个辅助索引树遍历3次找到指定的主键,如果聚集索引的高度同样为3,那么需要对聚集索引进行三次查找,最终找到一个记录所在的页,因此一共需要进行6次逻辑IO才能得到最终的逻辑页。

六、简单总结下

  1. InnoDB使用B+Tree作为索引数据结构。
  2. 从物理存储结构上说,B-Tree和B+Tree都以页(4K)来划分节点的大小,但是由于B+Tree中中间节点不存储数据,因此B+Tree能够在同样大小的节点中,存储更多的key,提高查找效率。
  3. 影响MySQL查找性能的主要还是磁盘IO次数,大部分是磁头移动到指定磁道的时间花费。
  4. InnoDB存储引擎下索引的实现,(辅助索引)全部是依赖于主索引建立的(辅助索引中叶子结点存储的并不是数据的地址,还是主索引的值,因此,所有依赖于辅助索引的都是先根据辅助索引查到主索引,再根据主索引查数据的地址)。

部分参考文献

漫谈数据库索引

MySQL技术内幕 (豆瓣)

mysql索引的新手入门详解

深入理解MySQL索引原理和实现

爪哇滑小稽:面试的时候怎么和面试官讲解你对MySQL索引的理解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值