从上面图可知 B+树的叶子节点存放了所有的索引值,并且叶子结点之间以链表的形式相互关联,所以我们只需从最左的链表遍历的话即可查找所有的值,最常见的用途就是范围查找,而 B 树则不满足这范围查找,又或者说实现特别复杂,所以 Mysql 最终选择了使用 B+树实现这一功能。
1.1 B-Tree 索引(B+树)
先说明一下,虽然叫在MySQL
官方叫做 B-Tree 索引,但采用的是 B+树数据结构。
B-tree 索引能够加快访问数据的速度,不需要进行全表扫描,而是从索引树的根节点层层往下搜索,在根节点存放了索引值和指向下一个节点的指针。
下面看下单列索引的数据怎么组织的。
create table User(
name
varchar(50) not null,uid
int(4) not null,gender
int(2) not null, key(uid
) );
上面 User 表给 uid 列创建了一个索引,那么往表里插入 uid(96~102)的时候存储引擎是怎么管理索引的呢?看下面的索引树
1.在叶子节点存放所有的索引值,非叶子节点值是为了更快定位包含目标值的叶子节点
2.叶子节点的值是有序的
3.叶子节点之间以链表形式关联
下面在看一下多列(联合)索引的数据怎么组织的。
create table User(
name
varchar(50) not null,uid
int(4) not null,gender
int(2) not null, key(uid
,name
) );
给 User 表创建了联合索引 key(uid
,name
) 这种情况下他的索引树是如下图所示。
特点跟单列索引一样,不同之处在于他的排序,如果第一个字段相同时会按第二个索引字段排序
如何通过 B-tree 快速查找数据?
对于 InnoDb 存储引擎的 B-tree 索引,会按以下步骤通过索引找到行数据
-
如果使用了聚簇索引(主键),则叶子节点上就包含行数据,可直接返回
-
如果使用了非聚簇索引(普通索引),则在叶子节点存了主键,再根据主键查询一次上面 的聚簇索引,最后返回数据
对于 MyISAM 存储引擎的 B-tree 索引,会按以下步骤通过索引找到行数据
- 在 MyISAM 的索引树的叶子节点上除了索引值之外即没存储主键,也没存储行数据,而是存了指向行数据的指针,根据这个指针在从表文件查询数据。
1.2 Hash 索引(哈希表)
哈希索引是基于哈希表来实现的,只有精确匹配所有的所有列才能生效。
也就是说假设有个 hash 索引 key (col1,col2) 那么每次只有 col1 和 col2 两个字段都用才能够生效。因为生成 hash 索引的时候是根据一个 hash 函数对所有的索引列取 hash 值来实现的。
如下方图,有个 hash 索引 key(name)
当我们执行 mysql> select * from User where name='张三';
时怎么利用 hash 索引快速查找的?
-
第一步,计算出 hash 值,hash(张三) = 1287
-
第二步,定位行号,比如 key=1287 对应的行号为 3
-
第三步,找到指定行并且比较 name 列值是否为张三做个校验
2.常见索引种类(应用层面)
主键索引
create table User(
name
varchar(50) not null,uid
int(4) not null,gender
int(2) not null, primary key(uid
) );
主键索引是唯一的,通常以表的 ID 设置为主键索引,一个表只能有一个主键索引,这是他跟唯一索引的区别。
唯一索引
create table User(
name
varchar(50) not null,uid
int(4) not null,gender
int(2) not null, unique key(name
) );
唯一索引主要用于业务上的唯一约束,他跟主键索引的区别是,一个表可以有多个唯一索引
单列索引
create table User(
name
varchar(50) not null,uid
int(4) not null,gender
int(2) not null, key(name
) );
以某一个字段为索引
联合索引
create table User(
name
varchar(50) not null,uid
int(4) not null,gender
int(2) not null, key(name
,uid
) );
两个或两个以上字段联合组成一个索引。使用时需要注意满足最左匹配原则!
还有其他不常用的就不介绍了~
3.聚簇索引与非聚簇索引
什么是聚簇索引?
聚簇索引指的是他的 索引和行数据 在一起存储。也就是在一颗 B+树的叶子结点上存储的不仅是他的索引值,还有对应的某一行的数据。待会儿看图便知。
聚簇索引不是一种索引,而是一种数据存储组织方式 !!!
crreate table test( col1 int not null, col2 int not null, PRIMARY KEY(col1), KEY(col2) )
如上所示,表 test 由两个索引,分别是主键 col1 和 普通索引 col2。那么这俩索引跟聚簇非聚簇有啥关系呢?
会生成一个聚簇索引和一个非聚簇索引(二级索引),也就是说会组织两个索引树。主键索引会生成聚簇索引的树 以及以 col2 为索引的非聚簇索引的树。
InnoDb 将通过主键来实现聚簇索引 ,如果没有主键则会选选一个唯一非空索引来实现。如果没有唯一非空索引则会隐式生成一个主键。
下面看下聚簇索引和非聚簇索引在索引树上数据是怎么分布的,图片摘自《高性能 Nysql》
下图是聚簇索引的数据组织方式。col1 为主键索引的聚簇索引树
索引列是主键 col1
可以看出叶子结点除了存储索引值 列 col1 (3994700)值 之外还存储了其他列的值,如列 col2 (92813),如果还有别的列的话也会存储,或者换句话说聚簇索引树 在叶子节点上存储某个索引值对应的一行数据。
下图是非聚簇索引(二级索引)的数据组织方式。
索引列是 col2
与聚簇索引不同的是非聚簇索引在索引树叶子节点上除了索引值之外只存了主键值。而聚簇索引则存了一行数据。
假如有一条 sql 语句 :
select * from test where col2=93;
上面这条语句会经历两次从索引树查找过程:
1.第一步从非聚簇索引的索引树上找到包含 col2=93 的叶子节点,并定位到行的主键 3
2.第二步 根据主键 3 在从聚簇索引定位包含 主键=3 的叶子节点并返回全部行数据。
以上说的都是基于 InnoDb 存储引擎的,MyISAM 是不支持聚簇索引的,因为他的数据文件和索引文件是相互独立存储的 MyISAM 存储引擎的索引树的叶子节点不会寸主键值,而存一个指向对应行的地址或者说是指针,然后再从表数据文件里去找,如下面图所示。
结论:
- 聚簇索引:
通常由主键或者非空唯一索引实现的,叶子节点存储了一整行数据
- 非聚簇索引:
又称二级索引,就是我们常用的普通索引,叶子节点存了索引值和主键值,在根据主键从聚簇索引查
4.覆盖索引
覆盖索引就是指索引包含了所有需要查询的字段。
create table User(
name
varchar(50) not null,uid
int(4) not null,gender
int(2) not null, key(uid
,name
) );
假如表 User 有三个字段 User (name,uid,gender),且有个联合索引 key(name,uid)那么 执行如下面这条 sql 查询时就用到了 覆盖索引。
select name,uid from User where name in (‘a’,‘b’) and uid >= 98 and uid <=100 ;
上面这条 sql 语句使用了联合索引 key(name,uid),并且只需查找 name,uid 两个字段,所以使用了覆盖索引。覆盖索引有什么好处呢?先看一下下面这个图
上面这个图就是 联合索引 key(name,uid) 所对应的索引树,从图中可以看出,如果我们只需查询(name,uid)两个字段的话,从索引树就能得到我们需要查的数据。不需要找到索引值之后再从表数据文件定位对应的行数据了。
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
663)]
[外链图片转存中…(img-4hH7CJYs-1715540099663)]
[外链图片转存中…(img-XkNOJJCd-1715540099664)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!