当前位置: 代码迷 >> 综合 >> SELECT 嵌套查询引起的 DEPENDENT SUBQUERY 问题
  详细解决方案

SELECT 嵌套查询引起的 DEPENDENT SUBQUERY 问题

热度:19   发布时间:2023-11-22 03:50:11.0

在使用select嵌套查询时,当外层查询和内层查询使用到同一张表的别名的时候,就可能由于执行器优化导致执行顺序出现问题,从而出现不太符合常规的结果。

先看一个例子:

例子中有两张表,如下所示:

表 department:

表employee:

表结构和数据都比较简单,下面看一段SQL代码:

SELECT d.Name AS 'Department',  e.Name AS 'Employee',  e.Salary  
FROM Employee e  
JOIN Department d 
ON e.DepartmentId = d.Id
WHERE   (  SELECT COUNT(p1.Salary)FROM  Employee p1WHERE   p1.DepartmentId = e.DepartmentId  AND p1.salary > e.salary  ) < 1

这个代码是什么意思呢?

按照我们常规的思路,那应该先执行内层的select语句,然后再执行外层的语句。

我们先看一下内层sql在做什么事情,把代码拿出来,

SELECT COUNT(p1.Salary)
FROM  Employee p1 , Employee e
WHERE   p1.DepartmentId = e.DepartmentId  AND p1.salary > e.salary 

因为内层部门没有e,所以加上了一个e表,执行结果如下:

什么意思呢?其实内层代码就是要求出在同一个部门内,出现某个人A比某个人B薪水高的情况的数量。这里求出的数量是10。

接着,根据我们的思路,获取到内层查询结果后,那就是要将这个结果应用到外层查询中,所以,外层查询的where条件就变成了 where 10 < 1 ,显然,这是不成立的,那么整个外层查询应该是没有结果返回的。

所以,根据我们一步步的分析,整个查询的最终输出结果应该是没有任何数据的!!

但是并非如此,我们直接执行一下原始的sql代码,得到了如下的输出结果:

这是什么原因呢? where 条件不是不成立吗?

一脸懵逼的情况下,不知道到底发生了什么。遇事不决,EXPLAIN !

通过查看这个代码的执行计划,发现了一些问题,重点关注图中标注的查询类型:DEPENDENT SUBQUERY

这表示,这个子查询并不是我们认为的普通子查询,而是一个依赖子查询,什么意思呢?

通俗讲就是内层子查询需要依靠外层的查询结果进行。

这就有点反常了,我们通常都说是先执行内部,再执行外部,是外部依赖于内部的执行结果,内部怎么依赖外部的结果呢?这到底是怎么运行的呢?

网上搜了一下关于 DEPENDENT SUBQUERY 查询类型的相关介绍,大致了解了整个代码的运行过程。

在最开始运行时,会先执行外部的查询语句,此时因为where条件不足,会暂时忽略掉where,只做一个on条件下的表连接操作,得到的新的表信息会存到 join buffer 里面。如下所示,

然后,就要去执行内层的查询了,如何执行呢?

他会循环地每次拿着外层查询结果中的一行数据,并将这一行数据应用到内层的查询中。在这个例子里面,相当于每次拿着外层结果的一行数据去内层查询中进行查询,然后再将查询结果应用到 where 条件上,如果where条件满足,就返回这一行数据,否则就不返回。

也可以这样理解,我们先得到一个大的结果集,然后一行一行地去根据对应的条件进行筛选,看哪些行可以返回展示。

从这个描述中也可以发现,当行数较大时,这个查询效率会急剧下降,因为内层查询要运行N次(N为外层结果集的行数)。而按我们常规的分析,先执行内查询,再执行外查询,则只需要运行两次查询。

所以,在实际环境中,能避免时应该尽量避免使用这种查询方式,否则可能导致接口响应速度特别慢!

那这个查询的最终结果含义是什么呢?

含义就是:返回每一个部门内薪水最高的那个人的信息。

当然,如果我们将 1 改成 2,那就是返回每一个部门内薪水排前两位的人的信息。(当存在相同薪水时,人数会多)

在这种特别的情况下,使用这种查询方式确实较为方便快捷!

  相关解决方案