百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

说说 MySQL 子查询

wptr33 2024-11-17 16:43 75 浏览

前言

前两天开发找DBA解决一个含有子查询的慢sql,我们通过将其修改为关联查询和添加索引解决。考虑到 大多数开发并没有准确的理解 MySQL 的子查询执行原理。本文介绍如何解决子查询慢查的思路。

原理

首先 知其然,知其所以然。大部分子查询为什么慢?我们得了解 MySQL 关联查询和子查询的处理机制。

MySQL 在处理所有的查询的时候都强行转换为联接来执行,将每个查询包括多表中关联匹配,关联子查询,union,甚至单表的的查询都处理为联接,接着MySQL执行联接,把每个联接再处理为嵌套循环 (nest-loop);

很多使用子查询的人 想当然的认为 子查询会由内到外,先完成子查询的结果, 然后在用子查询来驱动外查询的表,完成查询。例如:select * from test where tid in (select aid from sub_test where gid=3)通常我们会想到该sql的执行顺序为:

a. 先从 sub_test 表中获取 gid=3的记录(3,4,5)

b. 然后和外面的查询做匹配 tid in (3,4,5)。

但是,实际上对于子查询,外部查询的每条符合条件的记录,都会把子查询执行一次。如果遇到子查询查询量比较大或者索引不合理的情况,sql就变慢查。

当我们使用explian查看包含子查询的执行计划时,尤其要注意select_type 字段的内容,如果包含 SUBQUERY , DEPENDENT SUBQUERY 就需要提高警惕。

官方含义为:

SUBQUERY:子查询中的第一个SELECT;

DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询 ,注意如果外部查询的结果集数量比较大,比如几十万上百万,就会执行几十万上百万次子查询,必然造成慢查。

优化策略

MySQL子查询优化策略大致分为:

  1. 半连接(semi-join): 半连接优化本质上是把子查询上拉到父查询中,与父查询的表做join/semi-join的操作。关键词上拉

  2. 物化子查询(Materialization):子查询的结果通常缓存在内存或临时表中。

  3. EXISTS strategy:把半连接转换为EXISTS操作。本质上是把父表的条件下推到子查询中关键词下推

一图胜千言 ,下图展示了 MySQL 针对子查询的优化策略

图片来自于 https://mariadb.com/kb/en/subquery-optimizations-map/

需要对图中做解释的是:

  1. 白色区域是常见的 子查询类型, x IN (SELECT ...) ,x= any(select),exists (select )。

  2. 白色区域越大说明使用频率越多,比如最常见的子查询是 x IN (SELECT ...)

  3. 有颜色的区域表示优化方法和策略,不同颜色代表不同的mysql 分支。

强烈安利 Mariadb 的一系列博客,里面有n篇文章介绍subquery的优化。阅读原文直达博客地址。

https://mariadb.com/kb/en/subquery-optimizations/

书上来的终觉浅,绝知此事要躬行。

优化案例

业务的sql 如下,该sql 执行超过1200ms ,被sql-killer kill掉,影响业务使用。

select app_name,pkg_version,zone,created_at 
from activity
where id in (
select MAX(id) AS id
from activity
where zone = 'qa' AND status = AND zanpkg_version != ''
AND namespace = 'qa'
group by app_name,zone)
order by id desc limit 500;

执行计划

第一步 MySQL 执行 select id, app_name,pkg_version,zone,created_at from activity order by id desc limit 500; 获取一个结果集

第二部 拿第一步中的结果500多行每一个记录去执行 子查询,每次遍历70w行左右。而且子查询里面没有合适的索引。

优化方法

1 where条件中zone=qa是固定值,group by zone 无意义,去掉group by zone。

2 针对 (zone, namespace, status) 加上组合索引。

3 改子查询为关联查询。

select a.app_name, a.zanpkg_version, a.zone, a.created_at 
from activity a, ( select MAX(id) AS mid
from activity
where zone = 'qa' AND status = 2 AND zanpkg_version != ''
AND namespace = 'qa'
group by app_name) b
where a.id = b.mid limit 500;

修改之后的sql执行时间在 300-500ms 之间。感觉还是慢,因为要对十几万的数据量做 聚合运算。

参考文章

https://www.cnblogs.com/zhengyun_ustc/p/slowquery3.html https://blog.csdn.net/kk185800961/article/details/49340589

https://blog.csdn.net/fly2nn/article/details/61924636

https://blog.csdn.net/fly2nn/article/details/61924637

https://blog.csdn.net/fly2nn/article/details/61924640

-The End-



相关推荐

oracle数据导入导出_oracle数据导入导出工具

关于oracle的数据导入导出,这个功能的使用场景,一般是换服务环境,把原先的oracle数据导入到另外一台oracle数据库,或者导出备份使用。只不过oracle的导入导出命令不好记忆,稍稍有点复杂...

继续学习Python中的while true/break语句

上次讲到if语句的用法,大家在微信公众号问了小编很多问题,那么小编在这几种解决一下,1.else和elif是子模块,不能单独使用2.一个if语句中可以包括很多个elif语句,但结尾只能有一个...

python continue和break的区别_python中break语句和continue语句的区别

python中循环语句经常会使用continue和break,那么这2者的区别是?continue是跳出本次循环,进行下一次循环;break是跳出整个循环;例如:...

简单学Python——关键字6——break和continue

Python退出循环,有break语句和continue语句两种实现方式。break语句和continue语句的区别:break语句作用是终止循环。continue语句作用是跳出本轮循环,继续下一次循...

2-1,0基础学Python之 break退出循环、 continue继续循环 多重循

用for循环或者while循环时,如果要在循环体内直接退出循环,可以使用break语句。比如计算1至100的整数和,我们用while来实现:sum=0x=1whileTrue...

Python 中 break 和 continue 傻傻分不清

大家好啊,我是大田。...

python中的流程控制语句:continue、break 和 return使用方法

Python中,continue、break和return是控制流程的关键语句,用于在循环或函数中提前退出或跳过某些操作。它们的用途和区别如下:1.continue(跳过当前循环的剩余部分,进...

L017:continue和break - 教程文案

continue和break在Python中,continue和break是用于控制循环(如for和while)执行流程的关键字,它们的作用如下:1.continue:跳过当前迭代,...

作为前端开发者,你都经历过怎样的面试?

已经裸辞1个月了,最近开始投简历找工作,遇到各种各样的面试,今天分享一下。其实在职的时候也做过面试官,面试官时,感觉自己问的问题很难区分候选人的能力,最好的办法就是看看候选人的github上的代码仓库...

面试被问 const 是否不可变?这样回答才显功底

作为前端开发者,我在学习ES6特性时,总被const的"善变"搞得一头雾水——为什么用const声明的数组还能push元素?为什么基本类型赋值就会报错?直到翻遍MDN文档、对着内存图反...

2023金九银十必看前端面试题!2w字精品!

导文2023金九银十必看前端面试题!金九银十黄金期来了想要跳槽的小伙伴快来看啊CSS1.请解释CSS的盒模型是什么,并描述其组成部分。...

前端面试总结_前端面试题整理

记得当时大二的时候,看到实验室的学长学姐忙于各种春招,有些收获了大厂offer,有些还在苦苦面试,其实那时候的心里还蛮忐忑的,不知道自己大三的时候会是什么样的一个水平,所以从19年的寒假放完,大二下学...

由浅入深,66条JavaScript面试知识点(七)

作者:JakeZhang转发链接:https://juejin.im/post/5ef8377f6fb9a07e693a6061目录...

2024前端面试真题之—VUE篇_前端面试题vue2020及答案

添加图片注释,不超过140字(可选)...

今年最常见的前端面试题,你会做几道?

在面试或招聘前端开发人员时,期望、现实和需求之间总是存在着巨大差距。面试其实是一个交流想法的地方,挑战人们的思考方式,并客观地分析给定的问题。可以通过面试了解人们如何做出决策,了解一个人对技术和解决问...