如果仅仅是死记硬背MySQL索引相关面试题一定是相当枯燥的,不容易记却容易忘,这里循序渐进的讲解有关索引有关知识点,让大家在理解的基础上记住一些面试常问的点。
索引其实是一种数据结构,能够帮助我们快速的检索数据库中的数据。
优点
缺点
MySQL主要的几种索引类型:1.普通索引 2.唯一索引 3.主键索引 4.组合索引 5.全文索引。
主键索引和唯一索引的区别:
主键必唯一,但是唯一索引不一定是主键;
一张表上只能有一个主键,但是可以有一个或多个唯一索引。
索引的数据结构主要有B+树和哈希表,对应的索引分别为B+树索引和Hash索引。InnoDB引擎的索引类型有B+树索引
和Hash索引
,默认的索引类型为B+树索引。
Hash索引
哈希索引是基于哈希表实现的,当我们要给某张表某列增加索引时,存储引擎会对这列进行哈希计算得到哈希码,将哈希码的值作为哈希表的key值,将指向数据行的指针作为哈希表的value值。这样查找一个数据的时间复杂度就是O(1),一般多用于精确查找。所以在= in <=>(安全等于的时候)塔的效率是非常,但我们开发一般会选择Btree,因为Hash会存在如下一些缺点。
B+树索引
相对于cpu和内存操作,磁盘IO开销很大,非常容易成为系统的性能瓶颈。为什么索引能提升数据库查询效率呢?根本原因就在于索引减少了查询过程中的IO次数。那么它是如何做到的呢?使用B+树。下面先简单了解一下B树和B+树。
B树
B树,这里的 B 表示 balance( 平衡的意思),B-树是一种多路自平衡的查找树,它类似普通的平衡二叉树,不同的一点是B树允许每个节点有更多的子节点。下图是 B树的简化图.
观察上图可见B树的两个特点:
B+树
B+Tree是在B-Tree基础上的一种优化,使其更适合实现外存储索引结构,InnoDB存储引擎就是用B+Tree实现其索引结构。
B+Tree相对于B-Tree有几点不同:
聚集索引介绍
聚簇索引就是按照每张表的主键构造一颗B+树,同时叶子节点中存放的就是整张表的行记录数据,也将聚集索引的叶子节点称为数据页。这个特性决定了索引组织表中数据也是索引的一部分,每张表只能拥有一个聚簇索引。
聚集索引的叶子节点就是整张表的行记录。InnoDB 主键使用的是聚簇索引。聚集索引要比非聚集索引查询效率高很多。
非聚集索引介绍
普通索引也叫二级索引,除聚簇索引外的索引,即非聚簇索引。
InnoDB的普通索引叶子节点存储的是主键(聚簇索引)的值
,而MyISAM的普通索引存储的是记录指针。
示例
create table user(
id int(10) auto_increment,
name varchar(30),
age tinyint(4),
primary key (id),
index idx_age (age)
)engine=innodb charset=utf8mb4;
id 字段是聚簇索引,age 字段是普通索引(二级索引)
填充数据
insert into user(name,age) values('张三',30);
insert into user(name,age) values('李四',20);
insert into user(name,age) values('王五',40);
insert into user(name,age) values('赵六',10);
insert into user(name,age) values('田七',20);
mysql> select * from user;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | 张三 | 30 |
| 2 | 李四 | 20 |
| 3 | 王五 | 40 |
| 4 | 赵六 | 10 |
| 5 | 田七 | 20 |
+----+--------+------+
聚簇索引存储结构
id 是主键,所以是聚簇索引,其叶子节点存储的是对应行记录的数据
非聚簇索引存储结构
age 是普通索引(二级索引),非聚簇索引,其叶子节点存储的是聚簇索引的的值
聚簇索引查询
如果查询条件为主键(聚簇索引),则只需扫描一次B+树即可通过聚簇索引定位到要查找的行记录数据。
如:select * from user where id = 3;
非聚簇索引查询
如果查询条件为普通索引(非聚簇索引),需要扫描两次B+树,第一次扫描通过普通索引定位到聚簇索引的值,然后第二次扫描通过聚簇索引的值定位到要查找的行记录数据。
如:select * from user where age = 40;
上面的非聚簇索引查询就是回表查询。
先通过普通索引的值定位聚簇索引值,再通过聚簇索引的值定位行记录数据,需要扫描两次索引B+树,它的性能较扫一遍索引树更低。
只需要在一棵索引树上就能获取SQL所需的所有列数据,无需回表,速度更快。
如果我们把上面的非聚簇索引查询的sql改下
select id,age from user where age = 30;
这个sql我们是不是就不用回表查询了,因为在非聚簇索引的叶子节点上已经有id和age的值。所以根本不需要拿着id的值再去聚簇索引定位行记录数据了。也就是在这一颗索引树上就可以完成对数据的检索,这样就实现了覆盖索引。
如果这个sql是
select id,age,name from user where age = 30;
那就不能实现索引覆盖了,因为name的值在age索引树上是没有的,还是需要拿着id的值再去聚簇索引定位行记录数据。但是如果我们对age和name做一个组合索引idx_age_name(age,name),那就又可以实现索引覆盖了。
如果我们创建了(age, name)的组合索引,那么其实相当于创建了(age)、(age, name)两个索引,这被称为最佳左前缀特性。因此我们在创建组合索引时应该将最常用作限制条件的列放在最左边,依次递减。
最左前缀匹配原则:在MySQL建立联合索引时会遵守最左前缀匹配原则,即最左优先,在检索数据时从联合索引的最左边开始匹配。
这是为什么呢?
我们这里以组合索引(age, name)来画一下索引树就明白了。
我们再仔细观察索引结构,可以看到索引key在排序上,首先按age排序,age相等的节点中,再按name排序。因此,如果查询条件是age或age和name联查时,是可以应用到索引的。如果查询条件是单独使用name,因为无法确定age的值,因此无法使用索引。
如果当我们创建好组合索引(age, name),那么下面的sql还需要回表查询吗?
select id,age,name from user where age = 30;
答案是否定的,因为id,age,name字段,在这个索引树上已经都有了,我们也不需要拿着id的值再去聚簇索引定位行记录数据了。
所以在实际开发中如果你创建了(age, name)的组合索引,那就根本无需再去单独创建age的索引。同时也建议创建组合索引,只是在创建的时候需要考虑将最常用字段的列放在最左边,依次递减
理解了上面聚集索引相对于非聚集索引的树的结构,对于什么时候索引会失效,理解起来就不那么难了。
声明: 公众号如需转载该篇文章,发表文章的头部一定要 告知是转至公众号: 后端元宇宙。同时也可以问本人要markdown原稿和原图片。其它情况一律禁止转载!