写点什么

MySQL- 技术专题 -mysql 的联合索引

发布于: 2020 年 10 月 13 日
MySQL-技术专题-mysql的联合索引

前言

最近在学习 MySQL 的存储引擎和索引的知识。看了许多篇介绍 MyISAM 和 InnoDB 的索引的例子,都能理解。

像这张索引图:

但许多文章讲述的都是单列索引,我很好奇联合索引对应的结构图是怎样的。

疑惑:联合索引的结构是怎样的

比方说联合索引 (col1, col2,col3),我知道在逻辑上是先按照 col1 进行排序再按照 col2 进行排序最后再按照 col3 进行排序。因此如果是 select * from table where col1 = 1 and col3 = 3 的话,只有 col1 的索引部分能生效。但是其物理结构上这个联合索引是怎样存在的,我想不懂。

解答:联合索引的结构

假设这是一个多列索引(col1, col2,col3),对于叶子节点,是这样的:


也就是说,联合索引(col1, col2, col3)也是一棵 B+Tree,其非叶子节点存储的是第一个关键字的索引,而叶节点存储的则是三个关键字 col1、col2、col3 三个关键字的数据,且按照 col1、col2、col3 的顺序进行排序。

配图可能不太让人满意,因为 col1 都是不同的,也就是说在 col1 就已经能确定结果了。自己又画了一个图(有点丑),col1 表示的是年龄,col2 表示的是姓氏,col3 表示的是名字。如下图:

PS:对应地址指的是数据记录的地址。

如图,联合索引(年龄, 姓氏,名字),叶节点上 data 域存储的是三个关键字的数据。且是按照年龄、姓氏、名字的顺序排列的。

因此,如果执行的是:

select * from STUDENT where 姓氏='李' and 名字='安';

或者

select * from STUDENT where 名字='安';

那么当执行查询的时候,是无法使用这个联合索引的。因为联合索引中是先根据年龄进行排序的。如果年龄没有先确定,直接对姓氏和名字进行查询的话,就相当于乱序查询一样,因此索引无法生效。因此查询是全表查询。

如果执行的是:

select * from STUDENT where 年龄=1 and 姓氏='李';

那么当执行查询的时候,索引是能生效的,从图中很直观的看出,age=1 的是第一个叶子节点的前 6 条记录,在 age=1 的前提下,姓氏=’李’的是前 3 条。因此最终查询出来的是这三条,从而能获取到对应记录的地址。

如果执行的是:

select * from STUDENT where 年龄=1 and 姓氏='黄' and 名字='安';

那么索引也是生效的。

而如果执行的是:

select * from STUDENT where 年龄=1 and 名字='安';


那么,索引年龄部分能生效,名字部分不能生效。也就是说索引部分生效。

因此我对联合索引结构的理解就是 B+Tree 是按照第一个关键字进行索引,然后在叶子节点上按照第一个关键字、第二个关键字、第三个关键字…进行排序。

最左原则

而之所以会有最左原则,是因为联合索引的 B+Tree 是按照第一个关键字进行索引排列的。

有助于理解联合索引的一个例子

最后

  1. 联合索引的最左原则就是建立索引KEY union_index (a,b,c)时,等于建立了(a)、(a,b)、(a,b,c)三个索引,从形式上看就是索引向左侧聚集,所以叫做最左原则,因此最常用的条件应该放到联合索引的组左侧。

  2. 利用联合索引加速查询时,联合查询条件符合“交换律”,也就是where a = 1 and b = 1 等价于 where b = 1 and a = 1,这两种写法都能利用索引KEY union_index (a,b,c)


引用

联合索引在B+树上的结构介绍

用户头像

我们始于迷惘,终于更高的迷惘。 2020.03.25 加入

一个酷爱计算机技术、健身运动、悬疑推理的极客狂人,大力推荐安利Java官方文档:https://docs.oracle.com/javase/specs/index.html

评论

发布
暂无评论
MySQL-技术专题-mysql的联合索引