深入理解mysql的联合索引

深入理解mysql的联合索引,第1张

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

像这张索引图:

PS:该图来自大神张洋的《MySQL索引背后的数据结构及算法原理》一文。

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

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

上网查阅了许多资料,总算有点眉目了。

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

PS:该图改自《MySQL索引背后的数据结构及算法原理》一文的配图。

也就是说,联合索引(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是按照第一个关键字进行索引排列的。

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

1. 对order by使用复合索引

order by和limit一起使用,避免引起全表扫描和数据排序是非常重要的,因此借助合适的索引提高查询效率。

使用联合索引

联合索引又叫复合索引,是由表中的几个列联合组成的索引。联合索引生效需满足最左前缀原则,即如果联合索引列为a,b,c三列,a,b,c 、a,b 、a生效,b,c、a,c、b、c等不生效(此处的顺序不是where条件后面的先后顺序,而是where条件中是否存在这些列,如果where中只存在a,c列,则不生效)。

索引生效,与where条件的顺序无关:

索引失效,与where条件的列是否存在有关:

带IN条件的联合索引失效

in的参数个数为1个,联合索引生效,大于1个,索引失效。所以使用了强制索引使联合索引生效。

原因分析:

第一、取决于B树的数据结构,单参数的IN只会得到一颗基于model子树,该子树的code本身是有序的,所以索引生效,查询效率高;多参数的IN会得到多颗基于model的子树,每颗子树的code字段是有序的,但是总体上可能不是有序的,所以索引失效,查询效率低。

第二、使用强制索引后,理论上无法保证order by的顺序,但是如果数据本身的特性,比如时间递增的这类数据,总体上还是有序的,笔者试过多中途径想要迫使强制索引得到错误的结果,结果都对了。强制索引需进一步研究。

2. 大数据量limit慎用

limit常用于分页中,有两种用法,三种写法:

偏移量offset较大的优化

limit偏移量较小时性能优秀,分页越到后面,偏移量递增,limit的性能会逐渐下降。

此时,通过子查询优化limit,效果如下:

以上数据来自一张超过2000万的MySQL单表,仅供参考,能够说明子查询明显能够提升效率,笔者开始尝试把子查询的order by去掉,发现查询效率又提升2倍,但是对比发现数据不正确,explain后发现查询优化器给出的子查询索引并不是id(此表建有多个索引,id是主键,区分度最高),这一点比较困惑。

ps:在sql语句中,limt关键字是最后才用到的。以下条件的出现顺序一般是:where->group by->having-order by->limit

mysql中查询第几行到第几行的记录

1、查询前n行

       查询第一行

2、查询第n行到第m行

        查询第4行到 第6行

3、查询后n行

查询最后一行

4、查询一条记录的下一条记录

查询一条记录的上一条记录

MySQL目前主要的索引类型有下面几种:

与前面的普通索引类似,但是他的索引列的值必须是唯一的,所以叫唯一索引,但是这个索引字段如果是空值是可以的,具体创建方式如下:

主键索引是一种特殊的索引,一个表只能有一个主键,不允许有空值,一般是创建表的时候创建主键索引,而且一般习惯设置成自增的,因为对弈MySQL的底层B+树存储起来很方便

组合索引指多个字段上创建的索引,只有在查询时候,查询条件中使用了创建索引时的第一个字段,索引才会生效,他使用遵循最左前缀原则.

索引生效情况:

select * from table where name=1

select * from table where name=1 and city=2

select * from table where name=1 and city=2 and age=3

索引不生效情况:

select * from table where name=1 and age=3

select * from table where city=2 and age=3

select * from table where age=3

select * from table where city=2

这个遵循的是最左原则,具体MySQL底层对联合索引的存储以及为什么是最左原则,参考本人另外一篇文章最后一段就能看明白

https://www.jianshu.com/p/99aabf9611a3

全文索引主要是用来查找文本中的关键字,而不是直接与索引中的值相比较.fulltext索引跟其他索引大不相同,他更像是一个搜索引擎,而不是简单的where 语句的参数匹配,fulltext索引配合match(匹配)和against(反对) *** 作使用,而不是一般的where语句加上like,他可以在create table,alter table,create index使用


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/5905791.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-03-07
下一篇2023-03-07

发表评论

登录后才能评论

评论列表(0条)

    保存