我有以下人员表:
+---------+----------+-------------+
| name | dept_nbr | job_title |
+---------+----------+-------------+
| Michael | 14 | Programmer |
| Kumar | 14 | Programmer |
| Dave | 14 | Programmer |
| Jane | 14 | Manager |
| Carol | 37 | Programmer |
| Joe | 37 | Programmer |
| John | 59 | CEO |
+---------+----------+-------------+
问题:找到所有程序员少于3人的dept_nbr(部门)。
工作查询
SELECT DISTINCT dept_nbr
FROM Personnel AS P1
WHERE (SELECT COUNT(P2.dept_nbr)
FROM Personnel AS P2
WHERE P1.dept_nbr = P2.dept_nbr AND P2.job_title = 'Programmer') < 3;
结果:
37
59
备注:
部门14正确不包括在内,因为它有3个程序员(3个等于但不少于3个)。部门59没有程序员,也正确地包含在结果中。
我的问题:
执行上述查询时,通用SQL引擎如何进行?根据我的阅读,SQL执行顺序是(粗略地):From,Where,Group By,Having和Select。那么,以下是正确的吗?
1 - 外部查询将人员表的每一行作为P1传递给内部查询。
2.a - 内部查询将整个人员表扫描为P2,逐行,查找满足条件的行&#34; P1.dept_nbr = P2.dept_nbr AND P2。 job_title =&#39;程序员&#39;&#34;。
2.b - 内部查询完成整个表后,它会对匹配的dept_nbr值进行计数并将其返回给外部查询。
3 - 在外部查询中,如果从内部查询返回的计数满足条件&#34; WHERE(内部查询计数结果)&lt; 3&#34;,P1行的相应dept_nbr是SELECTed。
4 - 在外部查询处理的所有行之后,外部查询对结果执行DISTINCT并显示唯一的dept_nbr值。
我的理解是否正确?具体来说,外部查询是否在最后执行DISTINCT(步骤#4)?看来,通过这种方式,内部查询会执行冗余扫描(例如,它会在第一次传递中确实有答案的情况下处理dept_nbr = 14四次。)
我在sqlfiddle.com上使用MySQL 5.6测试了上述查询。
答案 0 :(得分:2)
执行上述查询时,通用SQL引擎如何进行? 根据我的阅读,SQL执行顺序是(粗略地):From,Where, 分组依据,拥有和选择。
这句话 - 通常 - 不正确。 SQL按您描述的顺序解析。但是,执行由优化程序确定,可能与原始查询几乎没有关系。请记住:SQL是一种描述性语言,而不是过程语言。它描述了结果集,而不是计算它的具体步骤。
也就是说,MySQL的执行计划比大多数其他数据库(特别是具有更好优化器的更高级数据库)更接近查询。并且,几乎所有数据库都将按照您为此查询描述的步骤继续进行。子查询中的聚合限制了优化的选择。
如果您想消除冗余,请在过滤之前执行select distinct
:
SELECT dept_nbr
FROM (SELECT DISTINCT dept_nbr FROM Personnel P1) P1
WHERE (SELECT COUNT(P2.dept_nbr)
FROM Personnel AS P2
WHERE P1.dept_nbr = P2.dept_nbr AND P2.job_title = 'Programmer'
) < 3;
您还可以通过聚合更简单地完成此操作:
select dept_nbr
from personnel
group by dept_nbr
having sum(job_title = 'Programmer') < 3;
答案 1 :(得分:1)
在查询之前添加EXPLAIN
(或EXPLAIN EXTENDED
),它应该为您提供解释计划,该计划将详细说明查询顺序的步骤。在尝试优化查询时,这是一个非常有用的工具。