一文通读Mysql索引

Posted 赵晓东-Nastu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文通读Mysql索引相关的知识,希望对你有一定的参考价值。

(1) 索引是什么?

数据本身之外,数据库还维护着一个满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,
这样就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是索引。

一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上。

(2)索引的目的

索引的目的在于提高查询效率,可以类比字典。

(3)索引的类型

B-Tree索引

B-Tree通常意味着所有的值都是按顺序存储的,并且每一个叶子到根的距离相同
在这里插入图片描述
B-Tree索引能够加快访问数据的速度,因为存储引擎不再须臾进行全表扫描来获取需要的数据,取而代之的是从索引的根节点开始搜索。
索引对多个值进行排序的依据是create table语句中定义索引时列的顺序 ,两个人的姓和名都一样,则根据他们的出生日期来排列查看。
可以使用B-Tree索引的查询类型,B-Tree索引适用于全键值、键值范围或键前缀查找。其中键前缀查找只适用于根据最左前缀的查找。前面所述的索引对如下类型的查询有效。
全值匹配
全值匹配指的是和索引中的所有列进行匹配。
匹配最左前缀
即只使用索引的第一列
匹配列前缀
也可以只匹配某一列的值的开头部分,例如前面提到的索引可用于查找所有以J开头的姓的人。这里也只使用了索引的第一列
匹配范围值
例如前面提到的索引可用于查找姓在Allen和Barrymore之间的人,这里也只使用了索引的第一列。
精确匹配某一列并范围匹配另外一列
也可用查找所有姓为Allen,并且名字是字母K开头的人,即第一列last_name全匹配,第二列first_name范围匹配。
只访问索引的查询
即查询只需要访问索引,而无需访问数据行。

哈希索引

哈希索引(hash index)基于哈希表实现,只有匹配索引所有列的查询才有效。

全文索引

全文索引是一种特殊类型的索引,它查找的是文本中的关键词,而不是直接比较索引中的值。全文索引和其他几类索引的匹配方式完全不一样。
全文索引更类似于搜索引擎做的事儿,而不是简单的where条件匹配。

(4)索引的优势

1、大大减少了服务器需要扫描的数据量。
2、索引可以帮助服务器避免排序和临时表。
3、索引可以将随机I/o变成顺序I/o。

(5)索引的劣势

实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占空间的。
虽然索引大大提高了查询速度,同时确会降低更新表的速度,如对表进行INSERT、UPDATE、DELETE。
因为更新表时,mysql不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段。
都会调整因为更新所带来的键值变化后的索引信息。

(6)InnoDB的索引模型

主键索引(聚集索引)
其实就是叶子节点的索引和真实的值存储在一个节点中,也就是数据文件和索引文件在一起存放
在这里插入图片描述
在这里插入图片描述
非主键索引采用的是非聚集索引
回表:
在这里插入图片描述

为什么建议InnoDB表必须创建一个主键,并且推荐使用整型的自增主键?
1、如果我们不创建主键,mysql会在底层帮我查找一个不重复的列,作为聚集索引,但是如果没有发现有唯一的列,那么mysql底层会帮我们创建一个默认的版本列来作为聚集索引,所以说mysql的innoDB的每一章表一定会并且只有一个聚集索引。
为什么不推荐使用uuid而推荐使用自增的?

  1. 长度问题:
    比较查询的效率更高,占用的资源更少,每一页占用的空间小,可以放更多的关键字,以降低B+树的高度
    而且B+树的叶子节点之间是双向链表对于范围查找效率很快
  2. 排序问题
    如果是自增,那么永远都是新创建节点,如果不是自增,就会造成节点分裂。性能降低
    索引底层原理:
    我们创建一个表并且指定主键,插入一些字段,执行查询发现

在这里插入图片描述

在这里插入图片描述
在底层页中的存储是按照顺序存储的,所以在查询的时候查询到4的时候就不继续往下查询。
在这里插入图片描述
如果没有页目录就会有一个问题就是如果查询id=2000,那么就会一直遍历下去。

在这里插入图片描述
这个时候就会根据页目录中的节点来查找对应的节点,效率有所提升,但是这个时候如果页越来越多,就变成了一个长链表,效率还是低。
这个时候就会先根据页目录中的节点来查找对应的节点,效率有所提升,但是这个时候如果页越来越多越就变成了一个个长链表。
在这里插入图片描述
最终的效果:

在这里插入图片描述
这样就和索引对应上了,也就形成了B+树
B+树的特点:

  1. 排好序的
  2. 叶子节点的值在非叶子节点中都是冗余存在的,但是不是全部冗余,只是冗余一部分(索引)
    所以说叶子节点其实存储的是 “page页”

什么是走索引什么是全表扫描
在这里插入图片描述
而我现在按照bcd进行建立索引
在这里插入图片描述
叶子节点只存储查询的值,如果我用select * 就会很不满足,如果全部记录在里面也不好,因为会和其他索引形成的冗余数据.
在这里插入图片描述如果我们把主键的id弄上,就可以了。
在这里插入图片描述
利用主键去查找,然后这个过程就叫回表。

(6) mysql索引分类

1、单值索引
即一个索引只包含单个列,一个表可以有多个单列索引
2、唯一索引
索引列的值必须唯一,但允许有空值。
3、复合索引
即一个索引包含多个列。

(7)索引的策略

一、聚簇索引

(InnoDB的索引模型)
聚簇索引并不是一种单独的索引类型,而是一种数据存储方式。但InnoDB的聚簇索引实际上在同一结构中保存了B-Tree索引和数据行。
当表有聚簇索引时,它的数据行实际上存放在索引的叶子页(leaf page)中。聚簇表示数据行和相邻的键值紧凑地存储在一起。
下图展示了聚簇索引中的记录是如何存放的,注意到,叶子页包含了行的全部数据,但是节点页只包含了索引列。
在这里插入图片描述
如果没有定义主键,InnoDB会选择一个唯一的非空索引代替,如果没有这样的索引,InnoDB会隐式定义一个主键来作为聚簇索引。
聚集的数据有一些重要的优点:
  A:可以把相关数据保存在一起,如:实现电子邮箱时,可以根据用户ID来聚集数据,这样只需要从磁盘读取少量的数据页就能获取某个用户全部邮件,如果没有使用聚集索引,则每封邮件都可能导致一次磁盘IO
  B:数据访问更快,聚集索引将索引和数据保存在同一个btree中,因此从聚集索引中获取数据通常比在非聚集索引中查找要快
  C:使用覆盖索引扫描的查询可以直接使用页节点中的主键值
聚集索引的缺点:
 A:聚簇数据最大限度地提高了IO密集型应用的性能,但如果数据全部放在内存中,则访问的顺序就没有那么重要了,聚集索引也没有什么优势了
  B:插入速度严重依赖于插入顺序,按照主键的顺序插入是加载数据到innodb表中速度最快的方式,但如果不是按照主键顺序加载数据,那么在加载完成后最好使用optimize table命令重新组织一下表
  C:更新聚集索引列的代价很高,因为会强制innodb将每个被更新的行移动到新的位置
  D:基于聚集索引的表在插入新行,或者主键被更新导致需要移动行的时候,可能面临页分裂的问题,当行的主键值要求必须将这一行插入到某个已满的页中时,存储引擎会将该页分裂成两个页面来容纳该行,这就是一次页分裂操作,页分裂会导致表占用更多的磁盘空间
  E:聚集索引可能导致全表扫描变慢,尤其是行比较稀疏,或者由于页分裂导致数据存储不连续的时候
  F:二级索引可能比想象的更大,因为在二级索引的叶子节点包含了引用行的主键列。
  G:二级索引访问需要两次索引查找,而不是一次
 在这里插入图片描述
聚簇索引的每一个叶子节点都包含了主键值、事务ID、用于事务和MVCC的回滚指针以及所有的剩余列,如果主键是一个列前缀索引,InnoDB也会包含完整的主键列和剩下的其他列

二、联合索引

现在创建一个索引为bcd,bcd不是主键索引,是联合索引

explain select * from t1 where b1 >7

如果这样会走索引吗?但是它走的是全表进行扫描,它是可以走索引的。
它认为它走全表扫描更快,如果走索引还要进行7次回表。所以成本是大于走索引的。

explain select * from t1 where b1 >6

但是如果是>6就有可能走索引,因为回表的次数少了。
在这里插入图片描述
为什么进行回表,因为查的是select * ,如果不是Select * 呢?
我直接查询它索引存储的
在这里插入图片描述
select b from t1 有几次走法?
(1)全表扫描
在这里插入图片描述
(2)索引扫描(bcd索引)
在这里插入图片描述
因为bcd索引扫描的时候,存储的数据是不完整的所以存储,所以存储的可能会多。

以上是关于一文通读Mysql索引的主要内容,如果未能解决你的问题,请参考以下文章

一文快速入门 MySQL 索引

企业数字化转型,一文通读什么是数字化中台?

企业数字化转型,一文通读什么是数字化中台?

纯干货万字长文,(强烈建议收藏)一文通读Git使用教程

MySQL索引知识 一文全了解,面试前必备

#yyds干货盘点#深入浅出,一文吃透mysql索引