2011-10-29 22 views
3

我有一個關於最佳方法的問題。我不確定哪種方法最適合數據被視爲可變大小。我應該使用SQL JOIN還是IN子句?

考慮以下3個表:

EMPLOYEE

EMPLOYEE_ID,EMP_NAME

PROJECT

PROJECT_ID,PROJ_NAME

EMP_PROJ(多對多的以上兩個表)

EMPLOYEE_ID,PROJECT_ID

問題:給定一個僱員,發現該員工與相關聯的所有項目的所有員工。

我已經試過這兩種方法..無論使用什麼樣的數據大小,兩種方法的差異只有幾毫秒。

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)" 

所以看起來就像方法二的執行計劃是稍微好一點,因爲 '成本'是60而不是方法1的85.這是分析這個問題的正確方法嗎?

即使對於各種各樣的許多組合,人們如何知道它會保持真實?

+0

通過查看2個備選方案的執行計劃可以更快地執行該方法。 – Icarus

+0

是的,我知道,但我永遠無法理解執行計劃。 – rk2010

+1

在此發佈執行計劃;如果你想識別你的瓶頸,這是最有用的信息 – Icarus

回答

4

這兩種方法可能導致次優性能,因爲它們都使用有效優化或不取決於DBMS的子查詢。

我會建議避免子查詢和使用JOIN什麼是意味着要使用,如:

編輯:

我糾正和simplyfied我的例子:

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 

我想應該注意的是,在一個查詢中使用不同的別名,多次參照相同的表是完全合法的。對於查詢來說,這在邏輯上看起來像兩個分開的表,它們碰巧具有相同的結構和數據。

+1

OP還應該確保'EMP_PROJ.PROJECT_ID'上有一個索引。 –

+0

我得到了一個與此查詢的SQL錯誤。我重試: '內部連接EMPLOYEE coll ep.EMPLOYEE_ID = coll.EMPLOYEE_ID' 但是這給了不正確的結果:它應該我只給了員工的名字。 但我想要的是:給定員工所屬的所有項目的所有員工。 – rk2010

+0

@Hanno Binder我已經嘗試過像這樣的連接,沒有使用子查詢,所有這些似乎都限制了我對特定僱員ID的具體結果。我迄今能夠得到正確結果的唯一方法是,如果我在一個單獨的子查詢中獲取給定Employee的Project ID。 – rk2010