复杂sql分析 以及 索引合并

复杂sql分析

简单的sql语句我们很简单的就可以分析出来它的执行计划,但是复杂的sql呢。例如

SELECT	*	FROM	single_table	WHERE(key1	>	'xyz'	AND	key2	=	748	)	OR(key1	<	'abc'	AND	key1	>	'lmn')	OR(key1	LIKE	'%suf'	AND	key1	>	'zzz'	AND	(key2	<	8000	OR	common_field	=	'abc'))	;

这条语句很难分析出来,遇到这样的语句怎么办呢,怎么分析它的范围匹配区间呢?

首先我们在为某个索引确定范围区间的时候只需要把用不到相关索引的搜索条件替换成true。

之所以把用不到索引的搜索条件替换为true,是因为我们呢不打算使用这些条件进行在该索引上进行过滤,所以不管索引的记录满不满足这些条件,我们都把他们选取出来,带到之后徽标的时候再使用他们过滤。

例如select * from table where key1 >100 and key2 > 10;

如果假设为用key1上的索引就可以简化为:select * from table where key1 > 100 and true;

如果假设为用key2上的索引就可以简化为:select * from table where true and key2 > 10;

根据小学的知识:a  and  b   只有a和b同时为true的时候结果才为true,只有所以key1>100 and true 可以简化为key1 > 100,因为最后的结果由key1 > 100决定。

所以如果假设为用key1上的索引就可以简化为:select * from table where key1 > 100;

根据上面的方法就可以简化上面的复杂sql为:

我们假设使用key1上的索引。

①key1 < 'abc' AND key1 > 'lmn',永远都不会满足这个条件,所以为false

②key1 like ‘%suf'  因为%在前面所以这个条件是用不到索引的

SELECT	*	FROM	single_table	WHERE(key1	>	'xyz'	AND	true	)	OR(false)	OR(true	AND	key1	>	'zzz'	AND	(true	OR	true))	;

false or 条件       根据小学的知识,最后的结果取决与条件为true还是false,所以简化为:条件 

SELECT	*	FROM	single_table	WHEREkey1	>	'xyz'	OR  key1	>	'zzz';

这就变成了简单的sql。可以很好的进行分析

继续简化因为条件为or,所以最后的结果取并集,所以就是最小的值key1 > 'xyz'

我们假设使用key2上的索引。

SELECT	*	FROM	single_table	WHEREkey2 = 748  or true	;

true  or   任何条件的结果:true

所以使用key2 需要扫描key2二级索引的全部记录,然后回表,这效率很低甚至不如全表扫描,所以优化器最后选择key1上的索引。

索引合并

mysql在一般的情况下执行一个查询最多会用到单个二级索引,但是也有些特上述情况可能用到多个二级索引,mysql中把这种使用到多个索引来完成一次查询的执行方法称之为:index_merge

explain的type = index_merge

索引合并有三种算法

Intersection合并

intersection就是交集的意思,就是某个查询可以使用多个二级索引,将多个二级索引中查到的结果取交集,例如

select * from table where key1 = 'a' and key2 = 'b';
假设使用intersection算法就是:

①从key1二级索引的B+树中取出key1=’a'的记录

②从key2 二级索引的B+树中取出key2=’a'的记录

③二级索引都是由二级索引列+id值组成,所以我们可以计算出两个结果集中id值的交集

④根据交集的id值进行回表操作,把结果返回给用户。

这⾥有同学会思考:为啥不直接使⽤idx_key1或者idx_key3只根据某个搜索条件去读取⼀个⼆级索引,然后回表后再过滤另外⼀个搜索条件呢?这⾥要分析⼀下 两种查询执⾏⽅式之间需要的成本代价。

只读取⼀个⼆级索引的成本:

按照某个搜索条件读取⼀个⼆级索引

根据从该⼆级索引得到的主键值进⾏回表操作,然后再过滤其他的搜索条件

读取多个⼆级索引之后取交集成本:

按照不同的搜索条件分别读取不同的⼆级索引

将从多个⼆级索引得到的主键值取交集,然后进⾏回表操作

虽然读取多个⼆级索引⽐读取⼀个⼆级索引消耗性能,但是读取⼆级索引的操作是顺序I/O,⽽回表操作是随机I/O,所以如果只读取⼀个⼆级索引时需要回表的记 录数特别多,⽽读取多个⼆级索引之后取交集的记录数⾮常少,当节省的因为回表⽽造成的性能损耗⽐访问多个⼆级索引带来的性能损耗更⾼时,读取多个⼆级索 引后取交集⽐只读取⼀个⼆级索引的成本更低。

MySQL在某些特定的情况下才可能会使⽤到Intersection索引合并:

情况⼀:⼆级索引列是等值匹配的情况,对于联合索引来说,在联合索引中的每个列都必须等值匹配,不能出现只匹配部分列的情况。

⽐⽅说下边这个查询可能⽤到idx_key1和idx_key_part这两个⼆级索引进⾏Intersection索引合并的操作:

SELECT * FROM single_table WHERE key1 = 'a' AND key_part1 = 'a' AND key_part2 = 'b' AND key_part3 = 'c';

⽽下边这两个查询就不能进⾏Intersection索引合并:

SELECT * FROM single_table WHERE key1 > 'a' AND key_part1 = 'a' AND key_part2 = 'b' AND key_part3 = 'c';

SELECT * FROM single_table WHERE key1 = 'a' AND key_part1 = 'a';

第⼀个查询是因为对key1进⾏了范围匹配,第⼆个查询是因为联合索引idx_key_part中的key_part2列并没有出现在搜索条件中,所以这两个查询不能进⾏ Intersection索引合并。

情况⼆:主键列可以是范围匹配

⽐⽅说下边这个查询可能⽤到主键和idx_key1进⾏Intersection索引合并的操作:

SELECT * FROM single_table WHERE id > 100 AND key1 = 'a';

为啥呢?凭啥呀?突然冒出这么两个规定让⼤家⼀脸懵逼,下边我们慢慢品⼀品这⾥头的⽞机。这话还得从InnoDB的索引结构说起,你要是记不清麻烦再回头看 看。对于InnoDB的⼆级索引来说,记录先是按照索引列进⾏排序,如果该⼆级索引是⼀个联合索引,那么会按照联合索引中的各个列依次排序。⽽⼆级索引的⽤ 户记录是由索引列 + 主键构成的,⼆级索引列的值相同的记录可能会有好多条,这些索引列的值相同的记录⼜是按照主键的值进⾏排序的。

所以重点来了,之所以 在⼆级索引列都是等值匹配的情况下才可能使⽤Intersection索引合并,是因为只有在这种情况下根据⼆级索引查询出的结果集是按照主键值排序的。

so?还是没看懂根据⼆级索引查询出的结果集是按照主键值排序的对使⽤Intersection索引合并有啥好处?⼩伙⼦,别忘了Intersection索引合并会把从多个⼆ 级索引中查询出的主键值求交集,如果从各个⼆级索引中查询的到的结果集本身就是已经按照主键排好序的,那么求交集的过程就很easy啦。假设某个查询使⽤ Intersection索引合并的⽅式从idx_key1和idx_key2这两个⼆级索引中获取到的主键值分别是:

从idx_key1中获取到已经排好序的主键值:1、3、5

从idx_key2中获取到已经排好序的主键值:2、3、4

那么求交集的过程就是这样:逐个取出这两个结果集中最⼩的主键值,如果两个值相等,则加⼊最后的交集结果中,否则丢弃当前较⼩的主键值,再取该丢弃的 主键值所在结果集的后⼀个主键值来⽐较,直到某个结果集中的主键值⽤完了,如果还是觉得不太明⽩那继续往下看:

先取出这两个结果集中较⼩的主键值做⽐较,因为1 < 2,所以把idx_key1的结果集的主键值1丢弃,取出后边的3来⽐较。

因为3 > 2,所以把idx_key2的结果集的主键值2丢弃,取出后边的3来⽐较。

因为3 = 3,所以把3加⼊到最后的交集结果中,继续两个结果集后边的主键值来⽐较。

后边的主键值也不相等,所以最后的交集结果中只包含主键值3。

别看我们写的啰嗦,这个过程其实可快了,时间复杂度是O(n),但是如果从各个⼆级索引中查询出的结果集并不是按照主键排序的话,那就要先把结果集中的主 键值排序完再来做上边的那个过程,就⽐较耗时了。

另外,不仅是多个⼆级索引之间可以采⽤Intersection索引合并,索引合并也可以有聚簇索引参加,也就是我们上边写的情况⼆:在搜索条件中有主键的范围匹配 的情况下也可以使⽤Intersection索引合并索引合并。为啥主键这就可以范围匹配了?还是得回到应⽤场景⾥,⽐如看下边这个查询:

SELECT * FROM single_table WHERE key1 = 'a' AND id > 100;

假设这个查询可以采⽤Intersection索引合并,我们理所当然的以为这个查询会分别按照id > 100这个条件从聚簇索引中获取⼀些记录,在通过key1 = 'a'这个 条件从idx_key1⼆级索引中获取⼀些记录,然后再求交集,其实这样就把问题复杂化了,没必要从聚簇索引中获取⼀次记录。别忘了⼆级索引的记录中都带有主 键值的,所以可以在从idx_key1中获取到的主键值上直接运⽤条件id > 100过滤就⾏了,这样多简单。所以涉及主键的搜索条件只不过是为了从别的⼆级索引得 到的结果集中过滤记录罢了,是不是等值匹配不重要。

当然,上边说的情况⼀和情况⼆只是发⽣Intersection索引合并的必要条件,不是充分条件。也就是说即使情况⼀、情况⼆成⽴,也不⼀定发⽣Intersection索引 合并,这得看优化器的⼼情。优化器只有在单独根据搜索条件从某个⼆级索引中获取的记录数太多,导致回表开销太⼤,⽽通过Intersection索引合并后需要回 表的记录数⼤⼤减少时才会使⽤Intersection索引合并。

Union合并

union是并集的意思,适用于不通索引的搜索条件之间使用or连接起来的情况。

情况⼀:⼆级索引列是等值匹配的情况,对于联合索引来说,在联合索引中的每个列都必须等值匹配,不能出现只出现匹配部分列的情况。

比如说下边这个查询可能⽤到idx_key1和idx_key_part这两个二级索引进行Union索引合并的操作:

SELECT * FROM single_table WHERE key1 = 'a' OR ( key_part1 = 'a' AND key_part2 = 'b' AND key_part3 = 'c');

而下边这两个查询就不能进行Union索引合并:

SELECT * FROM single_table WHERE key1 > 'a' OR (key_part1 = 'a' AND key_part2 = 'b' AND key_part3 = 'c');

SELECT * FROM single_table WHERE key1 = 'a' OR key_part1 = 'a';

第⼀个查询是因为对key1进行了范围匹配,第⼆个查询是因为联合索引idx_key_part中的key_part2列并没有出现在搜索条件中,所以这两个查询不能进行 Union索引合并。

情况⼆:主键列可以是范围匹配

情况三:使用Intersection索引合并的搜索条件

这种情况其实也挺好理解,就是搜索条件的某些部分使用Intersection索引合并的方式得到的主键集合和其他方式得到的主键集合取交集,比方说这个查 询:

SELECT * FROM single_table WHERE key_part1 = 'a' AND key_part2 = 'b' AND key_part3 = 'c' OR (key1 = 'a' AND key3 = 'b');

优化器可能采用这样的方式来执行这个查询:

先按照搜索条件key1 = 'a' AND key3 = 'b'从索引idx_key1和idx_key3中使⽤Intersection索引合并的方式得到⼀个主键集合。

再按照搜索条件key_part1 = 'a' AND key_part2 = 'b' AND key_part3 = 'c'从联合索引idx_key_part中得到另⼀个主键集合。

采用Union索引合并的方式把上述两个主键集合取并集,然后进行回表操作,将结果返回给⽤户。

当然,查询条件符合了这些情况也不⼀定就会采用Union索引合并,也得看优化器的心情。优化器只有在单独根据搜索条件从某个⼆级索引中获取的记录数比较少,通过Union索引合并后进行访问的代价比全表扫描更小时才会使用Union索引合并。

Sort-Union合并

Union索引合并的使⽤条件太苛刻,必须保证各个⼆级索引列在进⾏等值匹配的条件下才可能被⽤到,⽐⽅说下边这个查询就⽆法使⽤到Union索引合并:

SELECT * FROM single_table WHERE key1 < 'a' OR key3 > 'z'

这是因为根据key1 < 'a'从idx_key1索引中获取的⼆级索引记录的主键值不是排好序的,根据key3 > 'z'从idx_key3索引中获取的⼆级索引记录的主键值也不是 排好序的,但是key1 < 'a'和key3 > 'z'这两个条件⼜特别让我们动⼼,所以我们可以这样:

先根据key1 < 'a'条件从idx_key1⼆级索引总获取记录,并按照记录的主键值进⾏排序

再根据key3 > 'z'条件从idx_key3⼆级索引总获取记录,并按照记录的主键值进⾏排序

因为上述的两个⼆级索引主键值都是排好序的,剩下的操作和Union索引合并⽅式就⼀样了。

我们把上述这种先按照⼆级索引记录的主键值进⾏排序,之后按照Union索引合并⽅式执⾏的⽅式称之为Sort-Union索引合并,很显然,这种Sort-Union索引合 并⽐单纯的Union索引合并多了⼀步对⼆级索引记录的主键值排序的过程。

为啥有Sort-Union索引合并,就没有Sort-Intersection索引合并么?是的,的确没有Sort-Intersection索引合并这么⼀说, SortUnion的适⽤场景是单独根据搜索条件从某个⼆级索引中获取的记录数⽐较少,这样即使对这些⼆级索引记录按照主键值进⾏排序的成本也不 会太⾼ ⽽Intersection索引合并的适⽤场景是单独根据搜索条件从某个⼆级索引中获取的记录数太多,导致回表开销太⼤,合并后可以明显降 低回表开销,但是如果加⼊Sort-Intersection后,就需要为⼤量的⼆级索引记录按照主键值进⾏排序,这个成本可能⽐回表查询都⾼了,所以 也就没有引⼊Sort-Intersection。

索引合并注意事项

联合索引替代Intersection索引合并

SELECT * FROM single_table WHERE key1 = 'a' AND key3 = 'b';

这个查询之所以可能使⽤Intersection索引合并的⽅式执⾏,还不是因为idx_key1和idx_key3是两个单独的B+树索引,你要是把这两个列搞⼀个联合索引,那直 接使⽤这个联合索引就把事情搞定了,何必⽤啥索引合并呢,就像这样:

ALTER TABLE single_table drop index idx_key1, idx_key3, add index idx_key1_key3(key1, key3);

这样我们把没⽤的idx_key1、idx_key3都⼲掉,再添加⼀个联合索引idx_key1_key3,使⽤这个联合索引进⾏查询简直是⼜快⼜好,既不⽤多读⼀棵B+树,也不 ⽤合并结果,何乐⽽不为?

注意:不过⼩⼼有单独对key3列进⾏查询的业务场景,这样⼦不得不再把key3列的单独索引给加上

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

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

相关文章

为什么同一张显卡,深度学习的模型训练的时候,有时候成功了,有时候失败了

在同一张显卡上进行深度学习模型训练时&#xff0c;成功或失败的结果可能受到以下因素的影响&#xff1a; 随机性: 深度学习模型中的一些组件&#xff08;如权重初始化、数据的随机排列等&#xff09;可能涉及到随机性。这可能导致在每次训练时得到不同的结果&#xff0c;有时成…

Mybatis进阶知识

Mybatis的事务管理机制 在mybatis-config.xml文件中.可以进行mybatis的事务管理 <transactionManager type"JDBC"/> type的值有两个 JDBCMANAGED JDBC事务管理器 mybatis框架自己管理事务&#xff0c;自己采用原生的JDBC代码去管理事务 底层创建的事务管…

汇总区间算法(leetcode第228题)

题目描述&#xff1a; 给定一个 无重复元素 的 有序 整数数组 nums 。返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说&#xff0c;nums 的每个元素都恰好被某个区间范围所覆盖&#xff0c;并且不存在属于某个范围但不属于 nums 的数字 x 。列表中的每个区…

财务机器人(RPA)会影响会计人员从业吗?

财务机器人会对会计从业人员有影响。 不过是正面积极的影响。 它是财务人员工作的好助手好帮手。 具体展开聊聊财务RPA机器人是如何成为财务人员的好帮手。 财务机器人是在人工智能和自动化技术的基础上建立的、以软件机器人作为虚拟劳动力、依据预先设定的程序与现有用户系…

活用异常处理(try-except)

介绍 简要介绍Python的异常处理&#xff08;try-except&#xff09;。 基本语法 Try-except是Python中异常处理的基础。 作为例子&#xff0c;我们将解释执行除零时发生 ZeroDivisionError 的情况。 当除以零时&#xff0c;会出现以下错误。 print(1 / 0) # ZeroDivisionE…

蓝牙配对、连接和删除汇总

目的&#xff1a;处理PC连接蓝牙设备的配对、连接和删除操作&#xff0c;以及常见故障。 命令行配对蓝牙设备并连接 要求&#xff1a;配对BLUET043蓝牙&#xff0c;密码为4444&#xff0c;然后连接该蓝牙。操作步骤如下&#xff1a; Step1.下载 修复工具&#xff0c;然后安装…

利用python编写简易POC脚本

POC&#xff1a;概念证明&#xff0c;即概念验证&#xff08;英语&#xff1a;Proof of concept&#xff0c;简称POC&#xff09;是对某些想法的一个较短而不完整的实现&#xff0c;以证明其可行性&#xff0c;示范其原理&#xff0c;其目的是为了验证一些概念或理论。 声明&a…

三哥的黑科技,印度发布无线加热服装专利,冬季神器要来了

众所周知风和自由在冬天是不存在的&#xff0c;冬天只剩下冰冷的像刀子一样的风刮在你的脸上&#xff0c;哪怕穿的很厚&#xff0c;戴上全盔&#xff0c;也无法阻挡冰冷的风带走你身体温度&#xff0c;如果穿的特别多&#xff0c;骑车时候的舒适感和穿脱衣物的繁琐也是一大头疼…

【MySQL系列】Centos安装MySQL

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

vim常用键位总结

1、移动光标 按键作用h或←光标向左移动一个字符j或↓光标向下移动一个字符k或↑光标向上移动一个字符l或→光标向右移动一个字符Ctrl f或Page Down屏幕向下移动一页&#xff08;常用&#xff09;Ctrl b或Page Up屏幕向上移动一页&#xff08;常用&#xff09;Ctrl d屏幕向…

Kafka使用总结

1、Kafka是何如做到高性能的&#xff1f; a、消息批处理减少网络通信开销&#xff0c;提升系统吞吐能力&#xff08;先攒一波&#xff0c;消息以“批”为单位进行处理&#xff09; 生产端&#xff1a;无论是同步发送还是异步发送&#xff0c;Kafka都不会立即就把这条消息发送出…

【C++】算法库(复制操作、交换操作、变换操作)

C算法库 文章目录 C算法库复制操作copy , copy_ifcopy_ncopy_backward 交换操作swapswap_rangesiter_swap 变换操作transformreplacereplace_copy replace_copy_if 算法库提供大量用途的函数&#xff08;例如查找、排序、计数、操作&#xff09;&#xff0c;它们在元素范围上操…

java--StringBuilder、StringBuffer、StringJoiner

1.StringBuilder ①StringBuilder代表可变字符串对象&#xff0c;相当于是一个容器&#xff0c;它里面装的字符串是可以改变的&#xff0c;就是用来操作字符串的。 ②好处&#xff1a;StringBuilder比String更适合做字符串的修改操作&#xff0c;效率会比更高&#xff0c;代码…

Java入门:EditPlus的安装与配置讲解

1. 前言 Java是一种面向对象的编程语言&#xff0c;广泛应用于各种平台和设备。在Java开发过程中&#xff0c;一个好的集成开发环境&#xff08;IDE&#xff09;是非常重要的。EditPlus是一款简单易用的文本编辑器&#xff0c;它提供了一些方便的功能来支持Java开发。本文将介…

【开源】基于JAVA的木马文件检测系统

项目编号&#xff1a; S 041 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S041&#xff0c;文末获取源码。} 项目编号&#xff1a;S041&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 木马分类模块2.3 木…

Leo赠书活动-13期 【以企业架构为中心的SABOE数字化转型五环法】文末送书

Leo赠书活动-13期 【以企业架构为中心的SABOE数字化转型五环法】文末送书 ✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客…

记录 | xshell输出错乱解决

输出错乱问题&#xff1a; 解决方法&#xff1a;

VS Code使用 CMake 或 Makefile管理C++多文件编译

VS Code使用 CMake 或 Makefile管理C多文件编译 一、Cmake方式1、文件结构2、构建项目 二、Makefile方式1、文件结构2、Makefile3、构建项目 三、附件示例中使用到的文件及代码 使用 CMake 或 Makefile 是更加标准和灵活的方法来管理多文件编译。以下是一个简单的示例&#xff…

80个常用shell命令及简单用法

Shell命令是Linux和Unix系统中的基础&#xff0c;用于完成各种操作&#xff0c;如文件管理、程序执行、文本处理等。下面列举一些常用的Shell命令&#xff0c;并详细解释它们的功能及应用场景&#xff1a; ls - 列出目录内容 功能&#xff1a;列出指定目录中的文件和目录。应用…