我应该使用SQL JOIN还是IN子句?

时间:2011-10-29 02:51:43

标签: sql join

我对最佳方法有疑问。当数据被认为是可变的时候,我不确定哪种方法最好。

考虑以下3个表:

员工

EMPLOYEE_ID,EMP_NAME

PROJECT

PROJECT_ID,PROJ_NAME

EMP_PROJ (上述两个表中有多对多)

EMPLOYEE_ID,PROJECT_ID

问题:在给定EmployeeID的情况下,找到与此员工关联的所有项目的所有员工。

我以两种方式尝试过这种方法。无论使用何种大小的数据,这两种方法的差别仅为几毫秒。

SELECT EMP_NAME FROM EMPLOYEE
WHERE EMPLOYEE_ID IN (
    SELECT EMPLOYEE_ID FROM EMP_PROJ    
    WHERE PROJECT_ID IN (
        SELECT PROJECT_ID FROM EMP_PROJ p, EMPLOYEE e
        WHERE p.EMPLOYEE_ID = E.EMPLOYEE_ID 
        AND  E.EMPLOYEE_ID = 123)

select c.EMP_NAME FROM
(SELECT PROJECT_ID FROM EMP_PROJ 
  WHERE EMPLOYEE_ID = 123) a
JOIN 
EMP_PROJ b
ON a.PROJECT_ID = b.PROJECT_ID
JOIN 
EMPLOYEE c
ON b.EMPLOYEE_ID = c.EMPLOYEE_ID

截至目前,我预计每个人约有5000名员工和项目......但不知道存在多少种关系。 你会推荐哪种方法? 谢谢!

编辑: 方法1的执行计划

"Hash Join  (cost=86.55..106.11 rows=200 width=98)"
"  Hash Cond: (employee.employee_id = emp_proj.employee_id)"
"  ->  Seq Scan on employee  (cost=0.00..16.10 rows=610 width=102)"
"  ->  Hash  (cost=85.07..85.07 rows=118 width=4)"
"        ->  HashAggregate  (cost=83.89..85.07 rows=118 width=4)"
"              ->  Hash Semi Join  (cost=45.27..83.60 rows=118 width=4)"
"                    Hash Cond: (emp_proj.project_id = p.project_id)"
"                    ->  Seq Scan on emp_proj  (cost=0.00..31.40 rows=2140 width=8)"
"                    ->  Hash  (cost=45.13..45.13 rows=11 width=4)"
"                          ->  Nested Loop  (cost=0.00..45.13 rows=11 width=4)"
"                                ->  Index Scan using employee_pkey on employee e  (cost=0.00..8.27 rows=1 width=4)"
"                                      Index Cond: (employee_id = 123)"
"                                ->  Seq Scan on emp_proj p  (cost=0.00..36.75 rows=11 width=8)"
"                                      Filter: (p.employee_id = 123)"

方法2的执行计划:

"Nested Loop  (cost=60.61..112.29 rows=118 width=98)"
"  ->  Index Scan using employee_pkey on employee e  (cost=0.00..8.27 rows=1 width=4)"
"        Index Cond: (employee_id = 123)"
"  ->  Hash Join  (cost=60.61..102.84 rows=118 width=102)"
"        Hash Cond: (b.employee_id = c.employee_id)"
"        ->  Hash Join  (cost=36.89..77.49 rows=118 width=8)"
"              Hash Cond: (b.project_id = p.project_id)"
"              ->  Seq Scan on emp_proj b  (cost=0.00..31.40 rows=2140 width=8)"
"              ->  Hash  (cost=36.75..36.75 rows=11 width=8)"
"                    ->  Seq Scan on emp_proj p  (cost=0.00..36.75 rows=11 width=8)"
"                          Filter: (employee_id = 123)"
"        ->  Hash  (cost=16.10..16.10 rows=610 width=102)"
"              ->  Seq Scan on employee c  (cost=0.00..16.10 rows=610 width=102)"

所以看起来方法2的执行计划略好一些,因为'成本'是60而不是方法1的85.这是分析这个的正确方法吗?

即使对于各种多种组合,人们如何知道它仍然适用?

1 个答案:

答案 0 :(得分:4)

两种方法可能导致次优性能,因为它们都使用根据DBMS有效优化或不优化的子查询。

我建议避免使用子查询,并使用JOIN来表示要使用的内容,例如:

编辑:

我纠正并简化了我的例子:

select coll.EMP_NAME
from EMP_PROJ ep1
inner join EMP_PROJ ep2 on ep1.PROJECT_ID = ep2.PROJECT_ID
inner join EMPLOYEE coll on ep2.EMPLOYEE_ID = coll.EMPLOYEE_ID
where ep1.EMPLOYEE_ID = 123

我认为应该注意,在一个查询中使用不同的别名多次引用相同的表是完全合法的。对于查询,这在逻辑上“看起来”就像两个具有相同结构和数据的单独表。