MySQL的3种索引合并优化⭐️or到底能不能用索引?

news2025/2/24 5:28:43

MySQL的3种索引合并优化⭐️or到底能不能用索引?

前言

前文我们讨论过MySQL优化回表的多种方式:索引条件下推ICP、多范围读取MRR、覆盖索引等

这篇文章我们来聊聊MySQL提供的另一种优化回表的手段:index merge 索引合并

在阅读本文前,你需要了解MySQL的server层与存储引擎层如何交互、二级索引和聚簇索引的区别、回表等知识

如果同学不太了解这些知识可以回看前文:

MySQL的优化利器⭐️索引条件下推,千万数据下性能提升273%🚀

MySQL的优化利器⭐️Multi Range Read与Covering Index是如何优化回表的?

MySQL导致索引失效的八股文中有这样一条:使用or会导致索引失效

那么是不是所有场景都会失效呢?带着这个问题,我们往下看

案例使用上篇文章的座位表,并分别建立seat_code、student_id 两个二级索引

CREATE TABLE `seat` (
  `seat_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '座位ID',
  `seat_code` char(10) DEFAULT NULL COMMENT '座位码',
  `student_id` bigint(20) DEFAULT NULL COMMENT '座位关联的学生ID',
  PRIMARY KEY (`seat_id`),
  KEY `idx_student_id` (`student_id`),
  KEY `idx_seat_code` (`seat_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

index merge

正常情况下优化器只能选择一个它认为最成本最低的索引来生成执行计划

但在某些情况下可以使用多个索引进行索引合来优化

索引合并的优化分成三种方式:

  1. index merge intersection 交集索引合并
  2. index merge union 并集索引合并
  3. index merge sort union 排序并集索引合并

三种方式各自有什么不同呢?请按顺序往下看:

index merge intersection

index merge intersection 是用于交集的索引合并,交集往往和查询条件中的and相关

什么是交集?

比如有两个集合分别是(1,2,3)、(2,3,4),那么交集就是它们都存在的值(2,3)

举例这样一条SQL:

select * from seat 
where seat_code = 'caicaiseat' and student_id = 1

当不使用索引合并优化时,优化器可能选择seat_code索引或者student_id索引

当使用seat_code索引时,先在索引中找到满足seat_code = caicaiseat的记录,再回表查询聚簇索引获取完整记录

image.png

关闭交集索引合并的优化

SET optimizer_switch='index_merge_intersection=off';

查看执行计划

image.png

在这种场景下,可能存在很多满足seat_code = caicaiseat ,但是不满足 student_id = 1的记录

如果这些记录也需要回表,再回表后还是会被过滤,浪费资源来对这些记录进行回表

回表查询不仅仅是多查询一次,在这次查询中还可能是随机IO,查询量大的情况下,回表的代价是很高的

使用交集索引合并后

  1. 先使用seat_code索引找到满足 seat_code = caicaiseat 的条件
  2. 然后使用student_id索引找到满足 student_id = 1 的条件
  3. 接着根据主键seat_id对它们进行交集过滤,剩下的记录再进行回表,以此来减少回表的次数

(图中未回表是因为正好满足覆盖索引)

image.png

需要注意的是使用交集索引合并需要主键值需要有序,如果主键值乱序进行交集过滤,在回表时会产生随机IO,得不偿失

在二级索引中只有索引列相等时才对主键值进行排序,因此大部分使用交集索引合并的场景是等值比较=

开启交集索引合并,查看执行计划

type类型为索引合并,使用到这两个索引,附加信息显示用到交集索引合并,并且还用上覆盖索引不需要回表

由于seat座位表只存在主键seat_id、座位码seat_code、学生ID student_id,需要查询的列都在二级索引上,因此不用回表

image.png

有的同学可能注意到:为啥不把seat_code与student_id组成(seat_code,student_id)联合索引呢?

实际上(seat_code,student_id)联合索引也是可以用上索引的,但如果要单独查询student_id就会导致索引失效了

index merge union

index merge union是用于并集的索引合并,并集往往与查询条件or相关

什么是并集?

比如有两个集合分别是(1,2,3)、(2,3,4),那么并集就是它们都存在值的总和(1,2,3,4)

举例这样一条SQL

select * from seat 
where seat_code = 'caicaiseat' or student_id = 1;

当不使用index merge union的情况下,会直接全表扫描(聚簇索引),依次判断记录是否满足条件

index_merge_union=off 关闭并集索引合并

index_merge_sort_union 关闭排序的并集索引合并(是下一个要说明的索引合并,其在并集索引合并的基础上增加排序)

image.png

当使用index merge union的情况下

  1. 先使用seat_code索引找到满足条件seat_code = 'caicaiseat'的记录
  2. 再使用student_id索引找到满足条件student_id = 1的记录
  3. 然后将它们的主键值seat_id取并集后再回表查询,以此来减少开销

image.png

开启union优化,查看执行计划:已经使用index merge union

image.png

所以以后不要再傻乎乎的背八股文说or用不上索引啦~

使用index merge union的前提与index merge intersection类似也需要主键值有序

index merge sort union

由于or在某些场景下会让优化器认为回表成本大,不如全表扫描,从而导致索引失效

而index merge union的使用前提(主键有序)太苛刻,很多场景下还是无法使用索引

index merge sort union 排序的并集索引合并:对主键值无序的场景排序后再进行并集

比如这条SQL中

select * from seat where seat_code like 'a%' and student_id = 1

查询条件seat_code不再是等值比较,这样满足seat_code like 'a%'记录的主键值也不一定是有序的

而seat_code索引中满足student_id = 1的记录主键值是有序的

为了将seat_code索引满足条件的记录与seat_code索引满足条件的记录作并集

先对seat_code索引满足条件的记录进行排序,有序后再取并集

image.png

开启sort union后,查看执行计划:使用index merge sort union

image.png

情况与index merge union类似,使用前提可以是主键乱序,在主键乱序后对其进行排序再取交集

总结

index merge索引合并优化默认开启,分为intersection交集、union并集、sort union排序并集三种方式

index merge intersection使用的前提:and和可以使用多个索引且结果中主键有序,分别在对应的索引中找到满足条件的记录,对记录进行交集过滤后再进行回表,减少不必要的回表开销

index merge union 使用的前提:or和可以使用多个索引且结果中主键有序,分别在对应索引中找到满足条件的记录,对记录进行并集过滤后再进行回表,避免全表扫描

index merge intersection/union使用的前提都是需要主键有序,因为主键乱序需要先排序再进行交集/并集,否则会有随机IO

由于index merge union中or容易导致优化器认为回表成本大进而全表扫描,而满足主键有序的场景太苛刻,因此使用index merge sort union 在主键乱序的情况下排序再取并集

最后(不要白嫖,一键三连求求拉~)

本篇文章被收入专栏 由点到线,由线到面,构建MySQL知识体系,感兴趣的同学可以持续关注喔

本篇文章笔记以及案例被收入 gitee-StudyJava、 github-StudyJava 感兴趣的同学可以stat下持续关注喔~

有什么问题可以在评论区交流,如果觉得菜菜写的不错,可以点赞、关注、收藏支持一下~

关注菜菜,分享更多干货,公众号:菜菜的后端私房菜

本文由博客一文多发平台 OpenWrite 发布!

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

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

相关文章

windows + Mingw32-make 编译 PoDoFo库,openssl, libjpeg, Msys2工具的使用

参考: https://blog.csdn.net/sspdfn/article/details/104244306 https://blog.csdn.net/yaoyuanyylyy/article/details/17436303 https://blog.csdn.net/wxlfreewind/article/details/106492253 前期进行了各种摸索,由于Podofo依赖库比较多&#xff0c…

Android系统Launcher启动流程学习(一)init启动部分

init进程学习: 文件路径system/core/init/init.cpp 解析init.rc配置文件,首先开启ServiceManager和MediaServer等关键进程init进程fork启动Zygote服务进程处理子进程的终止(signal方式)提供属性服务的功能 int main(int argc, char** argv) {//注释一…

Problem I. Magic Potion--2018ICPC南京

解析&#xff1a; 对于英雄跑一边二分图匹配&#xff0c;记录res1 再跑一边二分图匹配&#xff0c;记录res2 答案即为res1min&#xff08;k&#xff0c;res2&#xff09; #include<bits/stdc.h> using namespace std; int n,m,k; int g[510][510],match[510],st[510]; b…

【Python全栈_公开课学习记录】

一、初识python (一).Python起源 Python创始人为吉多范罗苏姆&#xff08;荷兰&#xff09;&#xff0c;Python崇尚优美、清晰、简明的编辑风格。Python语言结构清晰简单、数据库丰富、运行成熟稳定&#xff0c;科学计算统计分析领先。目前广泛应用于云计算、Web开发、科学运算…

BlockingQueue解析

BlockingQueue其实就是阻塞队列&#xff0c;是基于阻塞机制实现的线程安全的队列。 BlockingQueue不同于普通的Queue的区别主要是&#xff1a; 通过在入队和出队时进行加锁&#xff0c;保证了队列线程安全支持阻塞的入队和出队方法&#xff1a;当队列满时&#xff0c;会阻塞入…

数据结构与算法【01】—绪论

专栏地址:数据结构与算法专栏 开源仓库:bigsai-algorithm仓库 ,欢迎支持 针对以前写的数据结构与算法系列重写(针对文字描述、图片、错误修复),改动会比较大,一直到更新完为止 前言 数据结构与算法是程序员内功体现的重要标准之一,且数据结构也应用在各个方面,业界更有…

3.18每日一题(奇偶性、奇偶性的平移、几何意义、配方、换元)

解法一&#xff1a;先配方&#xff0c;再用三角函数换元&#xff08;看见根号一般用三角函数&#xff09;&#xff0c;看见对称区间联想奇偶性&#xff0c;最后再用公式 解法二&#xff1a; 利用奇偶性的平移&#xff0c;令&#xff08;x-1&#xff09; t &#xff0c;对应的区…

ROS学习笔记(4):ROS架构和通讯机制

前提 前4篇文章以及帮助大家快速入门ROS了&#xff0c;而从第5篇开始我们会更加注重知识积累。同时我强烈建议配合B站大学的视频一起服用。 1.ROS架构三层次&#xff1a; 1.基于Linux系统的OS层&#xff1b; 2.实现ROS核心通信机制以及众多机器人开发库的中间层&#xff1b…

[H5动画制作系列]坐标转化问题一次搞清,一了百了

前言: 本次演示的坐标包括三个坐标层&#xff1a; 1.舞台上的某位置相对于舞台的全局坐标的坐标(黑色)。 2.舞台上蓝色实例内部某位置相对于该蓝色实例内部局部坐标的坐标(蓝色)。 3.舞台上蓝色实例内部的红色实例内部某位置相对该红色实例内部局部坐标的坐标(红色)。 舞台…

Linux Makefile变量详解

前言 我们是地球人。曾经为复杂的 Makefile 变量而苦恼过吗&#xff1f;这就是我们的用武之地。我们简化您的构建流程&#xff0c;以获得更快、更高效的结果。看看我们。 自 1976 年出现以来&#xff0c;Make 一直在帮助开发人员自动执行编译代码、构建可执行文件和生成文档的…

【ICCV2023】利用软对比学习和全能分类器提升模型在跨域场景发现新类别的能力...

论文标题&#xff1a; Boosting Novel Category Discovery Over Domains with Soft Contrastive Learning and All in One Classifier 论文链接&#xff1a;https://openaccess.thecvf.com/content/ICCV2023/html/Zang_Boosting_Novel_Category_Discovery_Over_Domains_with_So…

【Linux】 su 命令使用

su&#xff08;英文全拼&#xff1a;switch user&#xff09;命令用于变更为其他使用者的身份&#xff0c;除 root 外&#xff0c;需要键入该使用者 的密码。使用权限&#xff1a;所有使用者。 语法 su [选项] [-] [USER [参数]...] su命令 -Linux手册页 著者 作者&#xff1…

第二十二章 LaneAF框架结构以及接入MMDetection3D模型(车道线感知)

一 前言 近期参与到了手写AI的车道线检测的学习中去&#xff0c;以此系列笔记记录学习与思考的全过程。车道线检测系列会持续更新&#xff0c;力求完整精炼&#xff0c;引人启示。所需前期知识&#xff0c;可以结合手写AI进行系统的学习。 二 LaneAF接入openlane数据集 2.1 Lan…

Idea快速生成测试类

例如写写完一个功能类,需要对里面方法进行测试 在当前页面 按住CTRLSHFITT 选择你要生成的测试方法 点击OK,就会在test目录下在你对应包下生成对应测试类

k8s、调度约束

Kubernetes 是通过 List-Watch **** 的机制进行每个组件的协作&#xff0c;保持数据同步的&#xff0c;每个组件之间的设计实现了解耦 用户是通过 kubectl 根据配置文件&#xff0c;向 APIServer 发送命令&#xff0c;在 Node 节点上面建立 Pod 和 Container。 APIS…

axios 实现请求重试

前景提要&#xff1a; ts 简易封装 axios&#xff0c;统一 API 实现在 config 中配置开关拦截器 请求重试的核心是可以重放请求&#xff0c;具体实现就是在 axios 中&#xff0c;拿到当前请求的 config 对象&#xff0c;再用 axios 实例&#xff0c;就能重放请求。 在无感刷新…

MODWT(最大重叠离散小波变换)

MODWT 全称为 “多分辨率离散小波变换”&#xff08;Multiresolution Discrete Wavelet Transform&#xff09;&#xff0c;是一种基于小波分析的数据处理方法。 和传统的小波变换不同&#xff0c;MODWT 使用多种长度的小波滤波器来对信号进行多尺度分解。在 MODWT 中&#xf…

基于C语言实现扫雷小游戏

扫雷游戏 1. 扫雷游戏分析和设计1.1 扫雷游戏的功能说明1.2 游戏的分析和设计1.2.1 数据结构的分析 2. 扫雷游戏的代码实现3. 扫雷游戏的扩展 1. 扫雷游戏分析和设计 1.1 扫雷游戏的功能说明 使用控制台实现经典的扫雷游戏 游戏可以通过菜单实现继续玩或者退出游戏 扫雷的棋…

掌握微信批量添加好友技巧,让你的社交更高效

微信作为当今的热门通讯工具&#xff0c;在企业营销中扮演着越来越重要的角色。然而&#xff0c;微信并没有提供自动批量添加好友的功能&#xff0c;给运营者带来了不小的挑战。一个个手动添加不仅耗时&#xff0c;而且频繁操作还容易导致账号被封。本文将介绍几种手动批量添加…

你担心spring容器中scope为prototype的bean太大内存溢出吗?

你担心spring容器中scope为prototype的bean太大内存溢出吗&#xff1f; 提出假设 之前一直担心spring的scope为prototype的bean在一些高并发的场景下&#xff0c;吃不消吗&#xff0c;甚至会内存溢出&#xff0c;这样的担心不是没有道理的&#xff0c;&#xff08;以下是假设…