目录
前言
ok,紧接着就更新了我们mysql索引相关部分的下篇,在这篇中我们会学习到其底层所使用的B+树的特点以及两种索引类型,最后我们将接触到其实之前也了解过一些的索引操作,相信大家看完这两篇内容能对mysql中的索引部分有更深的认识!!
一、B+树的特点
如同上篇所说,索引是 B+树 的实际运用,这里我们两者结合再来回顾一下 B+树 的特点
叶子节点保存有数据,非叶子节点不要数据
-
非叶子节点:不存数据,只存储目录项,可以存储更多的目录项。
-
目录页:一个目录页可以管理更多的叶子 Page ,使树更 "矮胖" ,减少 I/O 次数,提高效率。
相比之下,B树 每一个节点内既包含目录项又包含数据,所以 B树 除了叶子节点有数据路上节点也会包含数据。
叶子节点全部用链表级联起来
- 链表级联:叶子节点用链表级联,便于进行范围查找,提高查询效率。
索引结构
-
InnoDB的索引结构:MySQL InnoDB 存储引擎使用 B+树 作为索引结构,一般我们建表插入数据时就是在该结构下进行CURD操作
-
主键索引:默认情况下,如果没有指定主键,MySQL 会自动生成一个隐藏列作为主键,一定会构建对应的B+树
-
普通索引:用户可以建立其他列的索引,这些索引也是 B+ 树结构。
复盘
-
Page分类:Page分为目录页和数据页。目录页只放各个下级 Page 的最小键值。
-
查找过程:自顶向下查找,只需加载部分目录页到内存,大大减少 I/O 次数。
-
索引构建:构建索引就是在MySQL内存中构建 B+ 树,以指定列作为 key 值。
与其他数据结构的对比
-
链表:线性遍历,效率低。
-
二叉搜索树:可能退化成线性结构,效率不稳定。
-
AVL & 红黑树:虽然平衡,但树高较高,I/O次数多。
-
Hash:适合点查询,但在范围查找方面表现不佳。
想借助动图来理解B+树的话,请点击这里
二、聚簇索引与非聚簇索引
非聚簇索引
-
MyISAM存储引擎,索引和数据分离,适合某些场景。
-
MyISAM 引擎同样使用 B+树 作为索引结果,叶节点的 data域 存放的是数据记录的地址。下图为 MyISAM 表的主索引, Col1 为主键。

其中, MyISAM 最大的特点是,将索引Page和数据Page分离,也就是叶子节点没有数据,只有对应数据的地址。
相较于 InnoDB 索引, InnoDB 是将索引和数据放在一起的
聚簇索引
- InnoDB存储引擎,数据和索引放在一起,提高查询效率。比如下图为 InnoDB存储 引擎的普通索引结构,其中Col3为索引列

两种方式建表产生的文件如下:

由此肉眼可见innodb就是聚簇索引,将索引和数据放一起,而myisam则是非聚簇索引,将索引和数据分开放
当然,MySQL 除了默认会建立主键索引外,我们用户也有可能建立按照其他列信息建立的索引,一般这种索引可以叫做辅助(普通)索引。
对于 MyISAM,建立辅助(普通)索引和主键索引没有差别,无非就是主键不能重复,而非主键可重复。
下图就是基于 MyISAM 的 col2 建立的索引,和主键索引没有差别

同样, InnoDB 除了主键索引,用户也会建立辅助(普通)索引,我们以上表中的 Col3 建立对应的辅助索引如下图

可以看到, InnoDB 的非主键索引中叶子节点并没有数据,而是只有对应记录的key值
所以通过辅助(普通)索引,找到目标记录,需要两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。这种过程,就叫做回表查询,为何 InnoDB 针对这种辅助(普通)索引的场景,不给叶子节点也附上数据呢?原因就是太浪费空间了
请注意:
-
所以一张表没有指明任何主键,mysql 默认会给表添加默认主键也会以 B+ 树结构呈现,只不过我没有设立主键就只能线性遍历。
-
如果我们指明主键默认我们的表会配上主键索引,会以我们自己设置的主键为 key值 设立主键索引。
-
如果我们指明主键索引,未来还想给其他列设置索引,我们可以手动添加。
-
添加之后会在 mysql 内部重新构建 B+ 树,以 MyISAM 为例会指向记录,如果是 InnoDB 保存的是主键值方便我们快速索引。换句话说,一个表可能会建立主键索引或者其他普通索引,不管建立任何索引最终在 mysql 中一张表可能会有多颗 B+ 树。
-
索引语法上分三类:主键索引、唯一键索引、普通索引,但其实宏观上就两类一个是主键索引 ,指明就用主键的没有指明就用默认的。一个是普通索引,包括唯一键索引。
三、索引操作
主键索引
创建主键索引
第一种方式
- 在创建表时直接指定 primary key
sql
create table test1(id int primary key, name varchar(30));
说明:在字段名后指定 primary key,MySQL会根据该列构建主键索引。
第二种方式
- 在创建表的最后指定某列或某几列为主键索引
sql
create table test2(id int, name varchar(30), primary key(id));
说明:在表定义的最后指定某列或某几列为主键。
第三种方式
- 创建表以后再添加主键
sql
create table test3(id int, name varchar(30));
alter table test3 add primary key(id);
说明:先创建表,再通过 alter table 添加主键。

主键索引的特点:
-
一个表中,最多有一个主键索引,当然可以是复合主键(约束的列)

-
主键索引的效率高(主键不可重复)
-
创建主键索引的列,它的值不能为 null,且不能重复
-
主键索引的列基本上是 int
查询索引
第一种方法
- 使用 show keys from 表名
sql
show keys from test1;
第二种方法
- 使用 show index from 表名
sql
show index from test1;
第三种方法
- 使用 desc 表名
sql
desc test1;

Key_name 索引名称 | Column_name 索引列 | Index_type 索引类型
删除索引
删除主键索引
- 第一种方法
sql
alter table 表名 drop primary key;
删除其他索引
- 第一种方法
sql
alter table 表名 drop index 索引名;
- 第二种方法
sql
drop index 素引名 on 表名;
唯一索引
创建
第一种方式
- 在表定义时指定 unique 唯一属性
sql
create table test4(id int primary key, name varchar(30) unique);
第二种方式
- 在表定义的最后指定某列或某几列为 unique
sql
create table test5(id int primary key, name varchar(30), unique(name));
第三种方式
- 创建表以后再添加唯一键
sql
create table test6(id int primary key, name varchar(30));
alter table test6 add unique(name);
添加唯一键后,表中会有两个 B+树 ,一个是主键索引,另一个是以指定列构建的唯一索引。

删除
使用 alter table 删除索引
sql
alter table 表名 drop index 索引名;
使用drop index 删除索引
sql
drop index 索引名 on 表名;


唯一索引的删除方式与普通索引相同,不能使用 drop unique。
-
删除唯一键不能用drop unique,用的是drop index。
-
来你会发现我们删除普通索引用的也是drop index。
-
说明unique索引本身也是一个普通索引。只不过指明它是unique是为了照顾表中的约束关系。
-
其实在索引层面,普通索引和唯一键索引都是一般索引。
-
最特殊的就是主键索引。
对此,我们可以对唯一索引总结出以下特点
-
一个表中可以有多个唯一索引(唯一是指 无重复数据)
-
查询效率高
-
如果在某一列建立唯一索引,必须保证这列不能有重复数据
-
如果一个唯一索引上指定 not null,等价于主键索引
普通索引
创建
第一种方式
- 在表定义的最后指定某列为索引
sql
create table test8(
id int primary key,
name varchar(20),
email varchar(30),
index(name)
);
第二种方式
创建完表以后指定某列为普通索引
sql
create table test9(
id int primary key,
name varchar(20),
email varchar(30)
);
alter table test9 add index(name);
第三种方式
创建一个索引名为 idx_name 的索引
sql
create table test10(
id int primary key,
name varchar(20),
email varchar(30)
);
create index idx_name on test10(name);
如果某列需要创建索引,但该列有重复值,应使用普通索引
复合索引
创建
sql
create table test11(
id int primary key,
name varchar(20),
email varchar(30)
);
create index idx_name_email on test11(name, email);
-
创建复合索引:我们以 name 和 email 两列建立索引。
-
索引数量:创建复合索引后,表中显示有三个索引,但这并不意味着新增了两个B+树。
-
单一B+树:复合索引实际上只构建了一颗B+树,而不是两颗。
-
键值组合:这颗B+树的键值是由 name 和 email 两列值组合而成。
-
搜索条件:在搜索时,这两列必须同时满足条件才能找到目标记录。
至于什么时候使用复合索引呢?
-
避免回表:InnoDB普通索引的叶子节点放的是表的主键的key值,这意味着需要回表查询。但如果以 name 和 email 构建复合索引,未来高频查询时,可以直接通过 name 和 email 查找,数据本身就在这颗复合索引的B+树里,无需回表。
-
索引覆盖:如果查询条件和返回值都在复合索引的列中,可以直接从索引中获取数据,无需回表,这种情况称为索引覆盖,覆盖的是主键索引。
-
最左匹配原则:MySQL在索引匹配时是从左侧开始向右匹配。例如,可以按 name 或 name 和 email 查找,但不能直接按 email 查找。
四、索引总结
-
频繁作为查询条件的字段:应该创建索引。
-
唯一性太差的字段:不适合单独创建索引,即使频繁作为查询条件。 示例:给性别打上索引,但性别只有男和女,构建出的B+树并不优秀。
-
更新非常频繁的字段:不适合作创建索引。 示例:考试信息更改太频繁,索引创建出来是为了方便查询,频繁修改不仅影响数据,还会调整索引结构。
-
不会出现在 where 子句中的字段:不应创建索引。 示例:某些字段从未在 where 子句中出现,创建索引没有意义。
其实还有一个全文索引,用于在长文本中查找特定的内容,而不仅仅是找到一条记录。但是这个就交给大家自行了解了!
