mysql索引总结

118 阅读4分钟

索引

种类

1. Hash

select * from sanguo where name='张三'

通过计算“张三”字段的Hash值所对应的数组下标,然后直接从数据中取出数据,并拿到那一行所对应的地址,进而查询那一行的数据。

但会出现哈希冲突。且如果要查询

select * from sanguo where name>'张三'

则是无能为力的,因为Hash可以快速的精确查询,但是不支持范围查询

如果做成索引的话,则需要进行全表扫描,效率十分低下。

tips:Hash表一般在等值查询的场景下使用较多,即只有key—>value的情况,一般用于Redis、Memcached等这些NoSQL的中间件。

2. B+树

Mysql选用B+树作为索引,可以提高查询索引时的磁盘IO(矮胖的B+树,树的高度比较矮),并且可以提高范围查询的效率,数据全部存在B+树中的叶子结点上,且是有序的。

B+树的一个节点一般存一页或页的倍数比较好。假设一个节点的大小大于1页,比如1.2页,那么读取这个节点也是一次读取2页,造成资源的浪费。

Mysql的基本存储结构也是页

  1. 每个数据页可以组成一个双向链表
  2. 每个数据页中的记录又可以组成一个单向链表
  1. 每个数据页都会为里面存储的记录生成一个页目录。通过主键查找某条记录时,可以在页目录中使用二分查找,定位到相应的槽,然后遍历该槽中对应分组中的记录即可快速找到指定的记录。
  2. 在其他列(非主键)作为搜索条件时:只能从最小记录开始依次遍历单链表中的每条记录。

假设写一条没有经过任何优化处理的sql语句:select * from user where name = ‘张三’

会执行这样一个步骤

  • 通过遍历双向链表,找到记录所在的页
  • 在该页中,查找相应的记录。如果是主键查询,就先去页目录查询,要是非主键查询,就只能遍历该页的单链表了。

索引类型

假设我们建了一个数据库表,有c1、c2、c3三列,前两列是int类型,最后一列是char类型,c1是主键

聚簇索引(主键索引)

当表有聚簇索引时,它的数据行实际上存放在索引的叶子页中。"聚簇"

表示数据行和相邻的键值紧凑地存储在一起。因为无法同时把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。

具体例子可以去看《mysql怎么运行的》 95页的图 (脑子里要有那两个图,同时知道是怎么走的)

提示:叶子节点记录的主键值和具体数据,非叶子节点是目录,记录的是主键值和下一个子节点的页号(方便往下走)。

二级索引(辅助索引)

二级索引的叶子节点包含的用户记录由 索引列和主键组成。如果通过二级索引去查找完整的用户记录,则需要执行回表操作:即通过二级索引找到主键值之后,再到聚簇索引种查找完整的用户记录。

95页的图,假设我们以c2为索引,这时候就会自动新建一颗B+树,在第99页的图。

这颗B+树和之前聚簇索引的B+树有以下不同:

  1. 页(叶子节点+ 内节点)是按照c2列的大小顺序排列的单向链表
  2. 叶子结点里存的是c2列的值 + 主键值。

所以当我们使用二级索引去找数据的时候,先是通过二级索引的B+树找到叶子节点的主键值,再通过这个主键值回表去主键索引的B+树中查找完整的记录。

联合索引(复合索引和多列索引。)

如果我们按照c2、c3列来进行排序的话,就会遵循这么一条规则:

  1. 先按照c2列进行排序
  2. 在c2列相同的情况下,再按照c3列进行排序。

具体图可以参考101页图片

非叶子节点由c2列、c3列和页号构成

叶子节点有c2、c3列和c1主键构成

覆盖索引

根据上面的先验知识,我们知道使用非主键索引会带来回表的操作,所以我们在进行查询操作的时候,如果查询的字段不是*,而正好是索引的字段,这样就不用进行回表查询了,这就叫覆盖索引

select name from t_student where name = '张三'。

如果在name处建立了索引,name直接返回该索引对应的B+树叶子结点的数据。