MySQL是如何优化in子查询的?

news2025/1/21 21:57:34

目录

前言

一、普通in子查询

二、物化表

三、SQL优化 

四、IN语句的优化方式

1. 使用子查询代替IN查询

2. 使用JOIN代替IN查询

3. 使用EXISTS代替IN查询

4. 使用索引优化IN查询

5. 优化查询语句

总结


前言

对于很多的开发小伙伴来说,在MySQL中进行in子查询是一个非常常见的操作。

虽然也有很多人说,尽量少用in子查询,in的数量过多会影响查询性能。

但其实MySQL做了不少的优化手段来保证in子查询的性能,大家也能在实际的业务中感受到in子查询的速度也没那么慢。

那今天就带大家了解一下,MySQL到底是怎么来优化in子查询的。


一、普通in子查询

首先,我们看一下MySQL是如何执行一个普通的in子查询的。

以一个简单的子查询为例:

select  * from user where name in ('b','f','g')

用户表B+Tree 树的数据结构,name为二级索引。

 

在这个图里,最上层的是根节点,中间的是非叶子节点,最下面的是叶子节点。

对于一个普通的二级索引来说,叶子节点存储的是索引key和主键id。

需要注意的是,二级索引在叶子节点中是按照key的顺序从小到大排序的,但是对应的主键id可不一定。

可能与大家想象的不同,MySQL在执行in子查询时,会把in语句中的条件当作一个个的区间,比如:

['b','b'],['f','f'],['g','g']

然后MySQL在二级索引树上,会先查询['b','b']这个区间,比如首先查询到第一个数据页中符合条件的第一条数据(b,2),获取到主键id=2之后,去聚簇索引回表查询所需的数据(因为我们使用的select *,需要获取到所有的列值)。

然后查询第三个数据页中符合条件的第三条数据(f,7),

不断的重复上面的动作。。。。

最后获取到一个结果集,返回到Server,再由Server返回到客户端。

看到这里大家是否可以感觉到,这样查询数据也太麻烦了,特别是当in子查询的条件越来越多时,如何保证性能呢?

下面,我们一起来看一下,MySQL是如何优化in子查询的。

二、物化表

首先,为了演示我们建两张表user和course,并建立两个二级索引idx_user_name和idx_course_name。

CREATE TABLE `user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';
CREATE TABLE `course` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(45) NOT NULL,
  `user_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_userId` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

下面以一个简单的子查询为例:在course表中查询name='中文'的user_id,并作为user表id的查询条件。 

select * from user where id in (select  user_id from course where name='中文')

对于一个这样普通的子查询来说,MySQL使用了一种叫作物化表的方式来提升性能。

什么意思呢?

就是将子查询的结果集去重后放入到一个临时表中,临时表的列就是子查询的结果集中的列。

去重的目的是为了让临时表尽可能的精简,因为在临时表中重复的列并没有什么意义。

当结果集比较小时,MySQL会为临时表使用memory引擎,并且为临时表中的列建立哈希索引。哈希索引的查询时间复杂度是O(1),查询速度是非常快的。

但是如果结果集比较大时,MySQL就会将临时表定义为InnoDB类型表,并且建立B+树索引,就像一个普通的表一样使用。

话说回来,将子查询转换为临时表以后,其实查询就变成了两张表的连接查询,也就是两个表的内连接。

一旦转换为内连接就好办了,经典的“小表驱动大表”的优化准则就可以派上用场了。

我们看一下MySQL优化器对上面的SQL优化后的结果:

select * from user u inner join course c on u.id=c.user_id where c.name='中文'

可以看到,MySQL将其转换为了内连接,并且以user为驱动表,course为被驱动表的方式进行了查询。

由于user表和course表上都有索引,那么此时这个sql的执行速度还是相当可以的。

以下是SQL语句的执行计划

三、SQL优化 

下图是生产环境的慢SQL截图

 执行该SQL语句,耗时3.742923秒

select a.cid, a.aid, a.create_time, a.channel_type, a.user_id, a.event_type, a.ip from testing_put_user_event_type a 
where a.create_time BETWEEN '2023-11-01 00:00:00' AND '2023-11-02 23:59:59' AND a.keep_type = 0 AND
(a.user_id in (164238,423998,500373,548715,589846,616448,699795,920701,988476,993033,1215905,1540914)) and event_type=6

 我们使用子查询代替IN查询,SQL耗时17ms,优化后的效果非常明显。

四、IN语句的优化方式

1. 使用子查询代替IN查询

IN查询在MySQL中是一个非常慢的查询方式,因为它需要对每个值进行比较。可以使用子查询来代替IN查询,子查询可以将结果缓存到内存中,从而提高查询效率。

2. 使用JOIN代替IN查询

使用JOIN代替IN查询也是一种优化方式。JOIN可以将两个或多个表连接起来,使查询更加高效。在使用JOIN时,需要注意查询语句的编写,避免出现笛卡尔积等问题。

3. 使用EXISTS代替IN查询

使用EXISTS代替IN查询也是一种优化方式。EXISTS只需要判断是否存在相关记录,而不需要返回具体的值,因此查询效率更高。

4. 使用索引优化IN查询

在MySQL中,索引是一种非常重要的优化方式。可以使用索引来优化IN查询,在使用索引时,需要注意索引的创建和使用,避免出现索引失效等问题。

5. 优化查询语句

在使用IN查询时,还可以通过优化查询语句来可以使用EXPLAIN命令来查看查询语句的执行计划,找出可能存在的性能瓶颈,从而进行优化。

总结

无论MySQL采用了哪种优化方法,只要知道了其实现的大致原理,对于使用者来说,就有了对应的优化思路。

特别建议大家写完SQL以后,习惯性的使用explain分析一下是否命中了索引,扫描的行数是否过多。

只有不断的实操,优化SQL的能力才会不断提升。

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

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

相关文章

Antlr4学习笔记

目录 背景 相关概念 流程说明 入门示例 简易计算器 环境准备 开发 java8方法提取 语法规则 常用的语法要点 设计语法 序列模式 选择模式 词法符号依赖 嵌套模式 总结 参考资料 背景 在阅读shardingjdbc-4.1.1代码时,发现一段sql解析的逻辑&#x…

极智开发 | H100服务器的庐山真面目

欢迎关注我的公众号 [极智视界],获取我的更多经验分享 大家好,我是极智视界,本文分享一下 H100服务器的庐山真面目。 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码和资源下载,链接:https://t.zsxq.com/0aiNxERDq H100 是英伟达最强显卡,当然其实也…

stable-diffusion 电商领域prompt测评集合

和GhostReivew一个思路,还是从比较好的图片或者是civitai上找一些热门的prompt,从小红书上也找到了不少的prompt,lexica.art上也有不少,主要是为了电商场景的一些测评: 小红书、civitai、Lexica、Liblib.ai、 depth o…

基于GEE云平台一种快速修复Landsat影像条带色差的方法

这是之前关于去除遥感影像条带的另一篇文章,因为出版商推迟了一年发布,所以让大家久等了。这篇文章的主要目的是对Landsat系列卫星因为条带拼接或者镶嵌产生的条带来进行的一种在线修复方式。 原文连接 一种快速修复Landsat影像条带色差的方法 题目&a…

app开发之后需要做什么

在完成app的开发之后,还有一系列的工作需要进行,以确保app的顺利上线和用户的良好体验。下面将从原理和详细介绍两个方面来介绍app开发之后需要做的工作。 一、原理介绍 1. 测试与调试:在app开发完成后,需要进行全面的测试与调试…

防范欺诈GPT

去年,ChatGPT的发布让全世界都感到惊讶和震惊。 突然间出现了一个平台,它比之前的任何其他技术都更深入地了解互联网。人工智能可以被训练成像阿姆一样说唱,以世界著名诗人的风格写作,并精确地翻译内容,以至于它似乎能…

初识Vue 解决vue在启动时生成的提示

让我为大家简单介绍一下吧&#xff01; Vue是一套用于构建用户界面的渐进式javaScript框架 当我们引入vue.js后 <script src"../js/vue.js"></script>我们发现&#xff0c;当我们打开网页时&#xff0c;控制台会出现以下内容 那我们该怎么解决呢&…

思科网络基础

目录 一、特殊的ip地址 1.一些基本概念 2.私有地址 3.子网划分 4.VLSM&#xff08;可变长子网掩码&#xff09; 5.CIDR&#xff08;无类域间路由-超网&#xff09; 二、IP头和一些基本概念 1.ip头 2.mtu 3.免费arp 一、特殊的ip地址 1.一些基本概念 网络位不变&…

卡尔曼家族从零解剖-(04)贝叶斯滤波→细节讨论,逻辑梳理

讲解关于slam一系列文章汇总链接:史上最全slam从零开始&#xff0c;针对于本栏目讲解的 卡尔曼家族从零解剖 链接 :卡尔曼家族从零解剖-(00)目录最新无死角讲解&#xff1a;https://blog.csdn.net/weixin_43013761/article/details/133846882 文末正下方中心提供了本人 联系…

玩转AIGC:如何选择最佳的Prompt提示词?

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

Spring、SpringMVC、Mybatis

一.Spring基础 1.Spring 框架是什么 Spring 是一款开源的轻量级 Java 开发框架&#xff0c;我们一般说 Spring 框架指的都是 Spring Framework&#xff0c;它是很多模块的集合&#xff0c;例如&#xff0c;Spring-core、Spring-JDBC、Spring-MVC 等&#xff0c;使用这些模块可…

Vite 的基本原理,和 webpack 在开发阶段的比较

目录 1&#xff0c;webpack 的流程2&#xff0c;Vite 的流程简单编译 3&#xff0c;总结 主要对比开发阶段。 1&#xff0c;webpack 的流程 开发阶段大致流程&#xff1a;指定一个入口文件&#xff0c;对相关的模块&#xff08;js css img 等&#xff09;先进行打包&#xff0…

【MySql】11- 实践篇(九)

文章目录 1. 大查询是否会把数据库内存打爆?1.1 全表扫描对 server 层的影响1.2 全表扫描对 InnoDB 的影响 2. 可不可以使用join?2.1 Index Nested-Loop Join2.2 Simple Nested-Loop Join2.3 Block Nested-Loop Join 3. join语句怎么优化?3.1 Multi-Range Read 优化3.2 Batc…

安装Oracle 11g Error in invoking target报错

在redhat7.5上安装Oracle 11g&#xff0c;安装过程中到86%时出现Error in invoking target报错 原因是由于操作系统版本过高&#xff0c;导致lib链接报错 [oracleemrtest ~]$ cd O R A C L E H O M E / s y s m a n / l i b / [ o r a c l e e m r t e s t l i b ] ORACLE…

没有PDF密码,如何解密文件?

PDF文件有两种密码&#xff0c;一个打开密码、一个限制编辑密码&#xff0c;因为PDF文件设置了密码&#xff0c;那么打开、编辑PDF文件就会受到限制。想要解密&#xff0c;我们需要输入正确的密码&#xff0c;但是有时候我们可能会出现忘记密码的情况&#xff0c;或者网上下载P…

canvas制作电子白板签名功能

Canvas是html5主要的画图工具&#xff0c;用户可以利用js在里面构思自己的创意&#xff0c;页面上很多手写签名是通过这个来完成的&#xff0c;让我们来用一个简单的例子作为抛砖引玉。 效果图 源代码 <html> <head> <meta charset"utf-8"> &l…

【脚本工具】视频抽帧、添加srt字幕朗读、添加背景音频

1.文章目录 看完本文章&#xff0c;你将能学会一下内容&#xff1a; 批量视频抽帧&#xff1b;添加srt字幕&#xff1b;添加srt配音&#xff1b;添加背景音乐&#xff1b;多视频片段合成一个新视频&#xff1b; 效果&#xff1a; 2.安装依赖 首先安装视频处理库opencv-pyth…

ERR invalid password

E:\Document_Redis_Windows\redis-2.4.5-win32-win64\64bit redis.conf

前端实现调用打印机和小票打印(TSPL )功能

Ⅰ- 壹 - 使用需求 前端 的方式 点击这个按钮&#xff0c;直接让打印机打印我想要的东西 Ⅱ - 贰 - 小票打印 目前比较好的方式就是直接用 TSPL 标签打印指令集, 基础环境就不多说了,这个功能的实现就是利用usb发送指令,现在缺少个来让我们能够和usb沟通的工具,下面这就是推…

代码随想录 Day35 动态规划04 01背包问题和完全背包问题 LeetCode T416 分割等和子集

背包问题 说到背包问题大家都会想到使用动规的方式来求解,那么为什么用动规呢,dp数组代表什么呢?初始化是什么,遍历方式又是什么,这篇文章笔者将详细讲解背包问题的经典例题0-1背包问题和完全背包问题的解题方式,希望能帮助到大家 1.暴力方式 有人一提到背包问题就只会使用动态…