MySQL 高级 —— 复合索引简介(多列索引)

引言

复合索引是指包含多个数据列的索引,与之概念相对的是单列索引,仅包含一个数据列。在大多数情况下,建立多列索引的好处都要多于单列索引。另外,复合索引最多支持16个列,但请一定不要让复合索引包含太多的列,这会导致索引空间的浪费。

索引是一种有序的数列,复合索引也是如此。

相对于单一索引,复合索引有一些必须注意的使用细节,否则很容易造成索引失效,降低查询速度。而要了解这些注意细节,就必须从复合索引的作用方式入手。

一、复合索引的作用方式

所谓“复合”,那一定是包含有多个,然而人们更愿意说“复合索引”胜于“组合索引”(实际上复合索引也叫组合索引),是因为复合更有 1 + 1 > 2 的感觉。换句话说,复合索引并不是多个单一索引的组合

为什么要强调这一点,是因为复合索引的作用方式在于不断地圈定范围,从左到右(左前缀匹配原则,下面会介绍),在前面索引查找的基础之上再进行索引查找,这就是复合索引的作用本质

复合索引的性能要优于多个单一索引,即便是复合索引与多个单一索引都用到了相同的列。

二、左前缀原则及复合索引的生效情况

这一节我们假设有一个包含三个列(c1, c2, c3)的复合索引,来讨论一下复合索引的 “左前缀原则” 。

如果有一个复合索引,包含了三个列,想要在SQL查询中使用该索引,必须使用复合索引靠左侧的列。可以仅使用 c1,也可以使用 c1 和 c2 ,当然也可以使用 c1,c2,c3。这就是复合索引的左前缀匹配原则

左前缀原则的索引生效,是由存储引擎对应的索引结构所决定的,在我们熟悉的 InnoDB 和 MyISAM 中,索引的数据类型是 BTree,正因为如此,我们才(一般)说索引是有序的,相对于其他的索引,比如哈希索引,我们同样可以通过哈希算法的特性了解到,这是一种随机的,无序的索引结构,它的作用在于存储更快。当然这些稍微有点题外话。

左前缀原则还有一些需要讨论的应用细节,仅仅通过 “必须使用靠左侧的列” 还是会在实际操作中存在疑惑。

如果只要求让复合索引生效,那只要使用第一个列,我们就可以说这个复合索引生效了。但生效并不意味着最快,复合索引有其本身的复杂度,如果想发挥出复合索引做大的性能效果,就需要尽可能的(在实际需求范围内)使用复合索引中更多的列。

在 WHERE 子句中,我们对一个查询进行筛选,如何能充分发挥复合索引的作用呢?

案例1:复合索引的最大化

WHERE c1 = x AND c2 = y AND c3 = z;

上述条件子句可以让包含 c1,c2,c3 的复合索引发挥最大的效果,当然,他们在 WHERE 子句中的书写顺序无关紧要,你也可以这样写:

WHERE c3 = x AND c2 = y AND c1 = z;

MySQL会自动对SQL语句进行优化,存储引擎依然会按照先查找 c1 再查找 c2 最后查找 c3 的顺序来执行,保证索引生效。

案例2:左前缀匹配的生效情况

WHERE c1 = x AND c3 = z;

上述条件中针对 c1 和 c3 进行了筛选,但根据左前缀匹配原则,上述子句并没有“靠左使用索引列”,中间跳过了 c2 ,因此这个筛选条件只用到了复合索引中的 c1 列,虽然复合索引生效,但是性能并不是最好的。

案例3:范围查询(包括 >、<=、<>、like等)中复合索引的生效情况

WHERE c1 > x AND c2 = y AND c3 = z;

上述条件中,c1 是范围查询,而 c2、c3 都是等值查询,这种情况依然只使用了复合索引的 c1 索引列。而c2、c3 的索引列并未生效。

WHERE c1 = x AND c2 < y AND c3 = z;

上述条件和前一种比较类似,在筛选条件中都用到了范围查询,但不同的是 c2 是范围查询,这时复合索引生效,但只用到了 c1 和 c2 索引列,并未使用 c3 索引列。

通过这两个例子,我们也可以发现,复合索引的各个索引列应该是一种从左到右逐级筛选的关系,因此,在建立复合索引的时候也要充分考虑存储数据的列与列的关系,找到当列等于某个值时,数据范围依次缩小的列,将这样的列共同组成复合索引。而且,在查找不确定的列值时,会导致复合索引中后定义的(索引定义中右侧的,不是WHERE 子句中的右侧)索引列失效。不过,失效并不意味着错误,根据具体的情况来讲,如果某个列真的是无法筛选等值的话,那么失效也是在所难免,应该辩证的去分析问题,一定不能为了追求索引的最大化,而导致业务逻辑错误! 

另外,IN() 函数也可以使索引正常生效,可以看做是一种多等值判断的情况。

案例4:order by 子句参与下的复合索引生效情况

WHERE c1 = x AND c3 = z ORDER BY c2 ;

这条语句对 c2 列进行了排序,同时对 c1 和 c3 进行了等值筛选,通过左前缀匹配规则,复合索引中的 c1 索引列肯定是生效的,c3 索引列肯定是未生效的,而 c2 索引列有没有生效呢?答案是否定的,也就是说,此条件中的复合索引仅有 c1 列生效,而 c2 和 c3 列都失效了。

关于order by 子句对索引的使用,情况比较复杂,我会在后面的学习中单独对其进行总结,因此最有效的方式还是结合 explain 来进行分析。

三、复合索引的创建语句

CREATE INDEX index_name ON table_name(col1, col2, col3) ;

例如,在 student 表中对年级、班级建立复合索引:

CREATE INDEX idx_grade_class ON student(grade_id, class_id);

四、使用执行报告查看复合索引的使用情况

使用复合索引后我们如何看到效果?我认为可以通过两种方式。第一种是直接观察SQL的执行速度,增加复合索引前和之后执行的时间可以为我们提供参考依据。

那么第二种方式就是通过 explain 执行报告,分析复合索引的使用情况。

还是以 student 表为例,来观察不同的SQL语句的执行报告,MySQL版本:5.7.27-log

表结构如下:

CREATE TABLE `student` (`stu_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '学生id',`grade_id` int(11) DEFAULT NULL COMMENT '年级id',`class_id` int(11) DEFAULT NULL COMMENT '班级id',`stu_name` varchar(20) DEFAULT NULL COMMENT '学生姓名',`stu_gender` char(1) DEFAULT NULL COMMENT '学生性别,1:男。2:女',`stu_age` int(11) DEFAULT NULL COMMENT '学生年龄',`address` varchar(50) DEFAULT NULL COMMENT '家庭住址',`enrollment_time` date DEFAULT NULL COMMENT '入学日期',PRIMARY KEY (`stu_id`),KEY `idx_grade_class` (`grade_id`,`class_id`)
) ENGINE=InnoDB AUTO_INCREMENT=79 DEFAULT CHARSET=utf8
EXPLAIN SELECT * FROM student WHERE grade_id = 1 ;
id  select_type  table    partitions  type    possible_keys    key              key_len  ref       rows  filtered  Extra   
--  -----------  -------  ----------  ------  ---------------  ---------------  -------  ------  ------  --------  -----1  SIMPLE       student  (NULL)      ref     idx_grade_class  idx_grade_class  5        const       28    100.00  (NULL)  
EXPLAIN SELECT * FROM student WHERE grade_id = 1 AND class_id = 3 ;
id  select_type  table    partitions  type    possible_keys    key              key_len  ref            rows  filtered  Extra   
--  -----------  -------  ----------  ------  ---------------  ---------------  -------  -----------  ------  --------  -----1  SIMPLE       student  (NULL)      ref     idx_grade_class  idx_grade_class  10       const,const       4    100.00  (NULL)
EXPLAIN SELECT * FROM student WHERE class_id = 3 ;
id  select_type  table    partitions  type    possible_keys  key     key_len  ref       rows  filtered  Extra        
--  -----------  -------  ----------  ------  -------------  ------  -------  ------  ------  --------  -------------1  SIMPLE       student  (NULL)      ALL     (NULL)         (NULL)  (NULL)   (NULL)      78     10.00  Using where 
EXPLAIN SELECT * FROM student WHERE grade_id IN(1, 2) AND class_id = 3 ;
id  select_type  table    partitions  type    possible_keys    key              key_len  ref       rows  filtered  Extra                  
--  -----------  -------  ----------  ------  ---------------  ---------------  -------  ------  ------  --------  -----------------------1  SIMPLE       student  (NULL)      range   idx_grade_class  idx_grade_class  10       (NULL)       5    100.00  Using index condition
EXPLAIN SELECT * FROM student ORDER BY grade_id, class_id ;
id  select_type  table    partitions  type    possible_keys  key     key_len  ref       rows  filtered  Extra           
--  -----------  -------  ----------  ------  -------------  ------  -------  ------  ------  --------  ----------------1  SIMPLE       student  (NULL)      ALL     (NULL)         (NULL)  (NULL)   (NULL)      78    100.00  Using filesort  

还有最后一个,范围查找,比较有意思:

EXPLAIN SELECT * FROM student WHERE grade_id > 2;
id  select_type  table    partitions  type    possible_keys    key     key_len  ref       rows  filtered  Extra        
--  -----------  -------  ----------  ------  ---------------  ------  -------  ------  ------  --------  -------------1  SIMPLE       student  (NULL)      ALL     idx_grade_class  (NULL)  (NULL)   (NULL)      78     32.05  Using where  
EXPLAIN SELECT * FROM student WHERE grade_id > 3;
id  select_type  table    partitions  type    possible_keys    key              key_len  ref       rows  filtered  Extra                  
--  -----------  -------  ----------  ------  ---------------  ---------------  -------  ------  ------  --------  -----------------------1  SIMPLE       student  (NULL)      range   idx_grade_class  idx_grade_class  5        (NULL)       1    100.00  Using index condition  
EXPLAIN SELECT * FROM student WHERE grade_id >= 3;
id  select_type  table    partitions  type    possible_keys    key     key_len  ref       rows  filtered  Extra        
--  -----------  -------  ----------  ------  ---------------  ------  -------  ------  ------  --------  -------------1  SIMPLE       student  (NULL)      ALL     idx_grade_class  (NULL)  (NULL)   (NULL)      78     32.05  Using where  
EXPLAIN SELECT * FROM student WHERE grade_id < 3;
id  select_type  table    partitions  type    possible_keys    key     key_len  ref       rows  filtered  Extra        
--  -----------  -------  ----------  ------  ---------------  ------  -------  ------  ------  --------  -------------1  SIMPLE       student  (NULL)      ALL     idx_grade_class  (NULL)  (NULL)   (NULL)      78     67.95  Using where  

范围查找所用索引的情况很令人费解,我暂时还没找到合理的解释,这种现象可能和表中数据太少有关系?所以关于SQL优化的理论知识,一定要配合 explain 执行计划来学习,有时候板上钉钉的结论依然可能是错误的。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558714.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL 高级 —— 索引实现的思考

引言 最近看了一个公开课&#xff0c;是有关MySQL对索引设计的思考。详细讲解了几种索引实现的设计思考与利弊辨析&#xff0c;讨论了为什么MySQL默认情况下会使用B树索引&#xff0c;B树索引又对B树做了哪些结构改进。 本片博客通过个人的学习理解和总结&#xff0c;由几种简…

Git 初学札记(十)—— Reset 回退的三种状态解析

引言 工作中经常会涉及到需要本地代码覆盖更新的操作。有时候可能是从远端git 上直接覆盖更新&#xff0c;或者是其他本地分支覆盖更新当前分支等等。这个时候就需要用到 reset 操作。 reset 操作分为三种类型&#xff1a;Soft、Mixed、Hard。今天我们就来说说这三种类型究竟…

MySQL 高级 —— 深入理解 InnoDB 与 MyISAM

引言 在文件系统中&#xff0c;MySQL将每个数据库&#xff08;也可以称之为schema&#xff09;保存为数据目录下的一个子目录。创建表时&#xff0c;MySQL会在数据库子目录下创建一个与表同名的.frm文件保存表的定义。因为MySQL使用文件系统的目录和文件来保存数据库和表的定义…

关于 OutOfMemoryError 的总结与解决方法

引言 本文总结自周志明的《深入理解Java虚拟机》第二章部分内容。 这部分内容&#xff0c;可以为后续性能调优方面的工作起到铺垫作用。 一、什么是 OutOfMemoryError OurOfMemory 简称“OOM”&#xff0c; 直译为“内存耗尽”或“内存溢出”&#xff0c;当然&#xff0c;并…

Windows误关闭资源管理器重启的办法

引言 有时候Windows系统在开机后&#xff0c;在桌面底部的任务栏中无法正常加载必要的网络连接图标或音量图标等&#xff0c;导致无法手动操作音量或连接网络。这时候就会需要打开“任务管理器”重新启动“资源管理器”使其重新加载这些必要的控制图标。 但是由于操作失误&am…

MySQL高级 —— 高性能索引

引言 最近一直在抱着《高性能MySQL&#xff08;第三版&#xff09;》研究MySQL相关热点问题&#xff0c;诸如索引、查询优化等&#xff0c;这阶段的学习是前一段时间MySQL基础与官方的“阅读理解”的进一步延伸。 书中第五章详细阐述了如何设计高性能的索引&#xff0c;以及索…

MySQL高级 —— 查询性能优化

引言 承接《MySQL高级 —— 高性能索引》&#xff0c;本篇博客将围绕《高性能MySQL&#xff08;第三版&#xff09;》第六章内容进行总结和概括。 与索引的部分一样&#xff0c;SQL优化也是广大程序员深入MySQL的又一条必经之路。希望通过本篇博客的总结&#xff0c;能够为我…

Java常用设计模式————适配器模式

引言 由于无法直接使用某个类中的方法而采取的一种中间类转换的策略。将一个类的接口转换成另一个接口&#xff0c;让原本接口不兼容的类可以兼容。 适配器模式可以分为三种&#xff1a;类适配器、对象适配器、接口适配器。它们之间的区别主要体现在适配器角色与被适配角色之…

Java常用设计模式————桥接模式

引言 在实际的业务中&#xff0c;经常会遇到多维度的概念组合&#xff0c;公园的门票&#xff0c;颐和园有年票、月票、日票&#xff0c;故宫也有年票、月票、日票。那么不同的公园和票种类型就可以视为两种不同的纬度&#xff0c;它们之间会形成相互组合的关系。 在类的设计…

Java常用设计模式————装饰者模式

引言 装饰者模式&#xff0c;又叫装饰器模式。它可以动态的将新功能附加到对象上。在对象功能扩展方面&#xff0c;它比继承更灵活&#xff0c;同时装饰者模式也体现了OCP原则。 在客户端调用使用了装饰者模式的对象时&#xff0c;就好像在使用构造器层层包裹核心对象&#x…

Java常用设计模式————组合模式

引言 组合模式&#xff0c;是一种类似递归算法的结构性设计模式&#xff0c;通过以简单的 List &#xff0c;组合本类对象&#xff0c;实现树状对象结构的“部分、整体”的层次。 它可以让调用程序不需要关心复杂对象与简单对象的区别&#xff0c;而统一地实现处理逻辑。 对…

Java常用设计模式————外观模式

引言 外观模式&#xff08;Facade Pattern&#xff09;&#xff0c;又叫“过程模式”。外观模式为子系统中的一组接口提供一个一致的入口&#xff0c;此模式定义了一个高层接口&#xff0c;这个接口使得这一组子系统更加易用。 一、案例分析 生活中有很多类似的案例&#xf…

Java常用设计模式————享元模式

引言 享元模式&#xff0c;也叫蝇量模式&#xff08;Flyweight Pattern&#xff09;。运用共享技术有效地支持大量细粒度的对象。 享元模式常用于系统底层开发&#xff0c;解决系统的性能问题。例如数据库连接池&#xff0c;里面都是创建好的连接对象&#xff0c;在这些连接对…

IDEA——常用基础设置

一、设置入口 File—>Settings... 或者 在工具栏的“小扳手”图标。 二、主题设置 三、编辑通用设置 设置面板中的 Editor 3.1 自动导包 可以设置IDEA自动为程序导包&#xff0c;在书写时加入准确的导包&#xff0c;在书写时优化导包&#xff08;自动去掉未使用的&#…

IDEA——常用快捷键

引言 总结 IDEA 的常用快捷键&#xff0c;除了部分快捷键与 Eclipse 保持一致之外&#xff0c;枚举更多的实用快捷键。 一、如何设置快捷键 在 Settings -> Keymap 中&#xff0c;下拉框里选择 Eclipse &#xff0c;即可将 IDEA 的快捷键设置为与 Eclipse 保持一致。但并…

IDEA——常用代码模板

引言 IDEA 提供了一些内置的代码模板&#xff0c;可以让开发者快速方便的使用&#xff0c;当然 eclipse 中也是有的&#xff0c;比如输入 syso 快速生成输出语句&#xff0c;main 快速生成主函数等。 idea 的模板设置都在 Settings --> Live Templates 和 General-->Po…

IDEA——Git 的设置与使用

引言 在本机下载好 Git 之后&#xff0c;再去在 IDEA 中设置 Git 相关的参数。详细的 Git 操作和 Eclipse 大同小异&#xff0c;可以移步至&#xff1a;《Git必知必会》 一、设置Git执行程序路径 二、导入一个新的远程 git 托管项目 打开 File ——> New ——> Project…

IDEA——Maven的配置与使用

引言 简单介绍一下如何在 idea 中配置maven&#xff0c;以及如何去使用 maven 。 一、配置 Maven home Maven home 和 settings 文件一般都需要进行重新设置&#xff0c;关联到本机已经安装好的 maven 版本&#xff0c;settings 这里可以使用默认&#xff0c;也可以设置为 ma…

Spring Cloud Alibaba——Nacos实现服务治理

引言 本博客总结微服务开发中各个微服务调用的实现&#xff0c;并使用 Nacos 完成服务注册和发现。 文章中会涉及到 maven 的使用&#xff0c;以及 spring boot 的一些知识。开发工具采用 IDEA 2020.2。 设计一个电商订单和商品购买微服务&#xff0c;实现微服务的注册发现与…

Spring Cloud —— Feign 实现服务调用

引言 本篇博客简单介绍 Feign 的基础知识和基本应用&#xff0c;以前一篇博客《Spring Cloud Alibaba——Nacos实现服务治理》为代码基础&#xff0c;实现更简单的微服务调用方式。 一、什么是Feign restTemplate 实现的微服务调用方式&#xff1a; // 调用商品微服务&…