2013-11-26 39 views
1

所以,讓我們說我有下面的表人和工資。這是一個1-N的關係,一個人可以有更多的工資。MySQL替代使用子查詢

**Person** 
id 
name 

**Wage** 
id 
person_id 
amount 
effective_date 

現在,我想查詢一個所有人及其最新工資清單。我可以通過執行以下查詢來獲得結果:

SELECT 
    p.*, 
    ( SELECT w.amount 
     FROM wages a w 
     WHERE w.person_id = p.id 
     ORDER BY w.effective_date 
     LIMIT 1 
    ) as wage_amount, 
    ( SELECT w.effective_date 
     FROM wages a w 
     WHERE w.person_id = p.id 
     ORDER BY w.effective_date 
     LIMIT 1 
    ) as effective_date 
FROM person as p 

問題是,我的查詢將有來自不同表的多個子查詢。我想盡可能提高效率。有沒有替代使用子查詢會更快,並給我相同的結果?

回答

1

正確的索引可能會使您的版本高效工作(即,wages(person_id, effective_date)上的索引)。

下產生具有單一的子查詢相同的結果:

SELECT p.*, w.amount, w.effective_date 
from person p left outer join 
    (select person_id, max(effective_date) as maxdate 
     from wages 
     group by personid 
    ) maxw 
    on maxw.person_id = p.id left outer join 
    wages w 
    on w.person_id = p.id and w.effective_date = maxw.maxdate; 

這個版本可能做出比上述更好的版本我們的索引:

SELECT p.*, w.amount, w.effective_date 
from person p left outer join 
    wages w 
    on w.person_id = p.id 
where not exists (select * from wages w2 where w2.effective_date > w.effective_date); 

注意,這些版本將返回多個當有兩個具有相同最大生效日期的「工資」時,單個行的行數。

+0

謝謝,完美的工作。如果存在具有相同生效日期的行,則「分組依據」解決多行問題。你們對我的版本更高效也是正確的。但是,由於我有更多的子查詢,因此將其與其他查詢進行比較並使用最適合該情況的方法非常好! – foxmulder

0

只要您確保使用索引,子查詢就非常高效。嘗試運行您的查詢EXPLAIN,看看它是否使用正確的索引

0

SELECT p.name,w.amount,MAX(w.effective_date)FROM人員P LEFT JOIN工資 W於w.person_id = p.id GROUP BY p.name

我沒有測試這個查詢。

+0

經過測試,它不會返回預期結果。 – foxmulder

+0

在您的查詢中存在'ORDER BY w.effective_date'。這裏沒有錯誤嗎?默認情況下,MySql使用ASC排序,並且您的查詢必須返回FIRST工資,而不是最後一個。 –

1

子查詢可以是一個很好的解決方案,就像Sam S在他的答案中提到的一樣,但它確實取決於子查詢,您正在使用的dbms和索引。有關子查詢與連接性能的良好討論,請參閱以下問題和答案:Join vs. sub-query

如果性能對您來說是個問題,則必須考慮使用dbms的EXPLAIN命令。它會告訴你如何構建查詢以及瓶頸在哪裏。根據其結果,您可能會考慮以其他方式重寫您的查詢。

例如,通常情況下,join會產生更好的性能,因此您可以根據以下答案重寫您的查詢:https://stackoverflow.com/a/2111420/362298並比較它們的性能。

請注意,創建正確的索引也會產生很大的差異。

希望它有幫助。

+0

非常感謝您的回覆。您提供的鏈接中的答案有一個工作解決方案和一些好的信息。 – foxmulder