Java小强个人技术博客站点    手机版
当前位置: 首页 >> DB >> MySQL慢查优化 循环/嵌套子查询(DEPENDENT SUBQUERY)

MySQL慢查优化 循环/嵌套子查询(DEPENDENT SUBQUERY)

10041 DB | 2023-6-28

虽然 MySQL5.6 引入了物化特性,但需要特别注意它目前仅仅针对查询语句的优化。对于更新或删除需要手工重写成 JOIN。

借助 explain 执行计划来分析索引失效的具体场景。看到 SQL 执行计划中select_type字段中出现“DEPENDENT SUBQUERY”时,要特别注意。


来看一个SQL

EXPLAIN SELECT t.id FROM student t WHERE t.is_del=0 and t.classin_err_times<10 
 AND (SELECT count(*) FROM classin_student ct WHERE ct.stu_id=t.id)<1 ORDER BY t.id DESC;

系统会给学员生成一个信息,生成后会录入到classin_student,这里要查找没有录入该信息的学员,就是ID不在classin_student表中的数据。


mysql慢查.jpg

看执行计划

DEPENDENT SUBQUERY

在SELECT或WHERE列表中包含了子查询,子查询基于外层

官方含义为:

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

DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询 。


MySQL执行逻辑是,先根据is_del和classin_err_times把外层数据查出来,然后根据外层的查询结果,又走了一个子查询,这个子查询的执行依赖于外层结果量


建议使用JOIN进行优化

EXPLAIN SELECT t.id FROM student t LEFT JOIN classin_student ct ON t.id = ct.stu_id 
WHERE t.is_del = 0  AND t.classin_err_times < 10 AND IFNULL(ct.id, 0) = 0;

查看执行计划,成了两个SIMPLE查询。

mysql慢查优化.jpg



附录:

DBA观点引用:MySQL 子查询的弱点:mysql 在处理子查询时,会改写子查询。

通常情况下,我们希望由内到外,先完成子查询的结果,然后再用子查询来驱动外查询的表,完成查询。

例如:

select * from test where tid in (select fk_tid from sub_test where gid=10)

通常我们会感性地认为该 sql 的执行顺序是:

sub_test 表中根据 gid 取得 fk_tid(2,3,4,5,6)记录,

然后再到 test 中,带入 tid=2,3,4,5,6,取得查询数据。

但是实际mysql的处理方式为:

select * from test where exists (
select * from sub_test where gid=10 and sub_test.fk_tid=test.tid)

mysql 将会扫描 test 中所有数据,每条数据都将会传到子查询中与 sub_test 关联,子查询不会先被执行,所以如果 test 表很大的话,那么性能上将会出现问题。


推荐您阅读更多有关于“ mysql 慢查询 子查询 DEPENDENT SUBQUERY ”的文章

上一篇:docker可视化管理工具-DockerUI 下一篇:Spring异步注解@Async线程池配置

猜你喜欢

发表评论:

评论:

回复 Java小强 评论于 2023-06-28 10:44
由于主表没有创建索引,而且数据特别少,因此走的是全表扫描。
这个我咨询了专业的DBA,在数据量特别少的时候,MySQL不走索引,这是正常的。