图解 MySQL 索引,清晰易懂,写得太好了!
共 7636字,需浏览 16分钟
·
2021-12-29 00:46
相关阅读:2T架构师学习资料干货分享
作者:shuaibing90
来源:www.xysycx.cn/articles/2020/12/05/1607146183637.html
什么是索引?
索引是辅助存储引擎高效获取数据的一种数据结构。
索引的分类
数据结构角度看索引
对上表进行横向查看可以了解到,B+tree 是 MySQL 中被存储引擎采用最多的索引类型。
这里浅尝辄止的谈一下 B+tree 与 Hash 和红黑树的区别。这方面系列面试题和答案全部整理好了,微信搜索互联网架构师,在后台发送:面试,可以在线阅读。
B+tree 和 B-tree
B+tree 是 B-Tree 的一个变种。(哦,对了,B-tree 念 B 树,它不叫 B 减树。。。)
B-tree : https://www.cs.usfca.edu/~galles/visualization/BTree.html
B+tree : https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html
因此,B+tree 单个节点的数量更小,在相同的磁盘 IO 下能查询更多的节点。
B+tree 和红黑树
B+tree 索引与 Hash 表
物理存储角度看索引
InnoDB 的索引
首先看一下 InnoDB 存储引擎中的索引,InnoDB 表的索引按照叶子节点存储的是否为完整表数据分为聚簇索引和二级索引。
全表数据就是存储在聚簇索引中的。
聚簇索引以外的其它索引叫做二级索引。
create table workers
(
id int(11) not null auto_increment comment '员工工号',
name varchar(16) not null comment '员工名字',
sales int(11) default null comment '员工销售业绩',
primary key (id)
) engine InnoDB
AUTO_INCREMENT = 10
default charset = utf8;
insert into workers(id, name, sales)
values (1, '江南', 12744);
insert into workers(id, name, sales)
values (3, '今何在', 14082);
insert into workers(id, name, sales)
values (7, '路明非', 14738);
insert into workers(id, name, sales)
values (8, '吕归尘', 7087);
insert into workers(id, name, sales)
values (11, '姬野', 8565);
insert into workers(id, name, sales)
values (15, '凯撒', 8501);
insert into workers(id, name, sales)
values (20, '绘梨衣', 7890);
包含 id(主键),name,sales 三个字段,指定表的存储引擎为 InnoDB。
然后插入 8 条数据
为了准确模拟,我们先把主键 id 插入 b+tree 得到下图
然后在此图基础上,我画出了高清版。
alter table workers add index index_name(name);
同样我们画出了二级索引 index_name 的 B+tree 示意图
图中可以看出二级索引的叶子节点并不存储一行完整的表数据,而是存储了聚簇索引所在列的值,也就是workers 表中的 id 列的值。
这两张示意图中 B+tree 的度设置为了 3 ,这也主要是为了方便演示。
实际的 B+tree 索引中,树的度通常会大于 100。
说了聚簇索引和二级索引 肯定要提到「回表查询」。
由于二级索引的叶子节点不存储完整的表数据,所以当通过二级索引查询到聚簇索引的列值后,还需要回到局促索引也就是表数据本身进一步获取数据。
分享资料:2T架构师学习资料干货分享
比如说我们要在 workers 表中查询 名叫吕归尘的人
select * from workers where name='吕归尘';
select id,name from workers where name='吕归尘';
这句 SQL 只查询了 id,和 name,二级索引就已经包含了 Query 所以需要的所有字段,就无需回表查询。
explain select id,name from workers where name='吕归尘';
使用 explain 查看此条 SQL 的执行计划
explain select id,name,sales from workers where name='吕归尘';
Using Index Condition
表示会先条件过滤索引,过滤完索引后找到所有符合索引条件的数据行,随后用 WHERE 子句中的其他条件去过滤这些数据行。Index Condition Pushdown (ICP)是 MySQL 5.6 以上版本中的新特性,是一种在存储引擎层
使用索引过滤数据的一种优化方式。ICP 开启时的执行计划含有 Using index condition 标示 ,表示优化器使用了 ICP 对数据访问进行优化。Using where
只是提醒我们 MySQL 将用 where 子句来过滤结果集。这个一般发生在 MySQL 服务器,而不是存储引擎层。一般发生在不能走索引扫描的情况下或者走索引扫描,但是有些查询条件不在索引当中的情况下。这里表明没有触发索引覆盖,进行回表查询。
MyISAM 的索引
说完了 InnoDB 的索引,接下来我们来看 MyISAM 的索引
以 MyISAM 存储引擎存储的表不存在聚簇索引。
他们的叶子节点是不存储表数据的,节点中存放的是表数据的地址,所以 MyISAM 表可以没有主键。
MyISAM 表的数据和索引是分开的,是单独存放的。
MyISAM 表中的主键索引和非主键索引的区别仅在于主键索引 B+tree 上的 key 必须符合主键的限制,
非主键索引 B+tree 上的 key 只要符合相应字段的特性就可以了。
索引字段特性角度看索引
create table persons
(
id int(11) not null auto_increment comment '主键id',
eno int(11) comment '工号',
eid int(11) comment '身份证号',
veid int(11) comment '虚拟身份证号',
name varchar(16) comment '名字',
primary key (id) comment '主键索引',
UNIQUE key (eno) comment 'eno唯一索引',
UNIQUE key (eid) comment 'eid唯一索引'
) engine = InnoDB
auto_increment = 1000
default charset = utf8;
alter table persons
add unique index index_veid (veid) comment 'veid唯一索引';
show index from persons
;命令我们看到已经成功创建了三个唯一索引。普通索引
主键索引和唯一索引对字段的要求是要求字段为主键或 unique 字段,
而那些建立在普通字段上的索引叫做普通索引,既不要求字段为主键也不要求字段为 unique。
另外,关注公众号互联网架构师,在后台回复:面试,可以获取我整理的 MySQL 系列面试题和答案,非常齐全。
前缀索引
前缀索引是指对字符类型字段的前几个字符或对二进制类型字段的前几个 bytes 建立的索引,而不是在整个字段上建索引。
例如,可以对 persons 表中的 name(varchar(16))字段 中 name 的前 5 个字符建立索引。
create index index_name on persons (name(5)) comment '前缀索引';
show index from persons;
char varchar binary varbinary
索引列的个数角度看索引
建立在单个列上的索引为单列索引
上文演示的都是单列索引 建立在多列上的称为联合索引(复合索引)
演示一下联合索引create index index_id_name on workers(id,name) comment '组合索引';
这条语句在我们演示表 workers 中建立 id,name 这两个字段的联合索引。借助 show index 命令查看索引的详细信息 操作后结果如下:
同样我们来看下联合索引的 B+tree 示意图