2010-10-04 101 views
72

我想知道如果我有一個加入查詢是這樣的 -SQL加入Vs SQL子查詢(性能)?

Select E.Id,E.Name from Employee E join Dept D on E.DeptId=D.Id 

子查詢這樣的事情 -

Select E.Id,E.Name from Employee Where DeptId in (Select Id from Dept) 

當我考慮性能其中兩個查詢會更快,爲什麼

也有一段時間,我應該更喜歡一個在另一個?

對不起,如果這太微不足道,以前問過,但我很困惑。此外,如果你們可以建議我工具我會用它來衡量兩個查詢的性能。非常感謝!

+3

另請參閱http://stackoverflow.com/questions/2577174/sql-join-vs-subquery – Lucero 2010-10-04 14:44:21

+3

@Lucero,這個問題被標記爲sql-server-2008,其中你提到的帖子標記爲MySql。你可以推斷答案是一樣的。性能優化在兩個RDBMS上完成的方式不同。 – 2012-04-25 15:35:54

回答

36

我希望先查詢要快,主要是因爲你有一個等價和顯式連接。根據我的經驗,IN是一個非常慢的運算符,因爲SQL通常將其評估爲由「OR」(WHERE x=Y OR x=Z OR...)分隔的一系列WHERE子句。

與所有這些SQL雖然,你的里程可能會有所不同。速度將取決於很多索引(你是否在兩個ID列上都有索引?這將有助於很多...)等等。

以更快的速度告訴100%確定性的唯一真正方法是開啓性能跟蹤(IO統計特別有用)並同時運行它們。確保在運行之間清除緩存!

+9

我對此回答有嚴重疑問,因爲絕大多數DBMS,絕對是SQL Server 2008及更高版本,都將單個ID子查詢(不相關,意思是:不引用多個外部查詢列)轉換爲相對較快的半聯接。此外,正如前面在另一個答案中指出的那樣,第一個真正的連接將返回一行,以便在每個事件中發現匹配的ID - 這對於唯一ID沒有任何影響,但會在其他地方給您帶來大量重複。用DISTINCT或GROUP BY對它們進行排序將是另一個嚴重的性能負載。檢查SQL Server Management Studio中的執行計劃! – 2013-12-27 09:32:51

+1

作爲OR等價物的IN子句適用於參數/值列表,但不適用於子查詢,它們通常被視爲聯接。 – 2013-12-27 09:55:01

2

表現應該是一樣的;在表格上應用正確的索引和集羣更重要(有關該主題的some good resources)。

(編輯,以反映更新後的問題)

+0

我更新了我的問題以更改查詢很少...感謝您的回覆。 – Vishal 2010-10-04 14:33:28

0

您可以使用解釋計劃來獲得客觀答案。

對於您的問題,an Exists filter可能會執行得最快。

+2

「一個存在過濾器可能執行速度最快」 - 可能不是,我認爲,雖然明確的答案需要測試實際數據。如果有多個行具有相同的查找值,則存在過濾器可能會更快 - 因此,如果查詢檢查其他員工是否從同一部門錄製過,則存在過濾器可能運行得更快,但在查看部門時可能不會表。 – 2010-10-04 15:05:20

+0

它會在最後一種情況下運行得慢嗎? – Snekse 2010-10-04 17:08:00

+0

這取決於優化器 - 在某些情況下,它可能,但通常我會期望非常相似的性能。 – 2010-10-05 12:47:10

9

開始查看執行計劃以查看SQl Server如何解釋它們的差異。您還可以使用Profiler實際運行多次查詢並獲得不同的結果。

我不希望這是如此可怕的不同,在那裏你可以得到使用中獲得真正的,大的性能提升聯接,而不是子查詢是當您使用相關子查詢。

EXISTS往往比這兩種的,當你在談論離開聯接要不是在左側的所有記錄的連接表更好,那麼NOT EXISTS往往是一個更好的選擇。

3

這兩個查詢可能不是語義等價的。如果一個員工爲多個部門工作(可能在我工作的企業中;誠然,這意味着您的表沒有完全標準化),那麼第一個查詢將返回重複的行,而第二個查詢則不會。爲了在這種情況下使查詢等效,DISTINCT關鍵字必須添加到SELECT子句中,這可能會影響性能。

請注意,有一個設計經驗法則規定一個表應該爲實體/類或實體/類之間的關係建模,但不能同時建模這兩個實體/類。因此,我建議您創建第三個表格,如OrgChart,來模擬員工和部門之間的關係。

4

性能是根據正在執行的數據量...

如果是20K左右的數據量。 JOIN工作得更好。

如果數據更像100k +,那麼IN效果更好。

如果你不需要來自另一個表的數據,那麼IN是好的,但是對於EXISTS來說最好還是更好。

我測試的所有這些標準和表都有適當的索引。

22

嗯,我相信這是一個「舊但金」的問題。答案是:「這取決於!」。 表演是一個非常微妙的主題,所以說:「永遠不要使用子查詢,總是加入」太愚蠢了。 在下面的鏈接,你會發現,我已經發現了一些基本的最佳實踐是非常有幫助的: Here 1 Here 2 Here 3

我有50000元的表格,結果我一直在尋找爲739元。

我在第一個查詢是這樣的:

SELECT p.id, 
    p.fixedId, 
    p.azienda_id, 
    p.categoria_id, 
    p.linea, 
    p.tipo, 
    p.nome 
FROM prodotto p 
WHERE p.azienda_id = 2699 AND p.anno = (
    SELECT MAX(p2.anno) 
    FROM prodotto p2 
    WHERE p2.fixedId = p.fixedId 
) 

,並花了7.9s執行。

我最後的查詢是這樣的:

SELECT p.id, 
    p.fixedId, 
    p.azienda_id, 
    p.categoria_id, 
    p.linea, 
    p.tipo, 
    p.nome 
FROM prodotto p 
WHERE p.azienda_id = 2699 AND (p.fixedId, p.anno) IN 
(
    SELECT p2.fixedId, MAX(p2.anno) 
    FROM prodotto p2 
    WHERE p.azienda_id = p2.azienda_id 
    GROUP BY p2.fixedId 
) 

,並花了0.0256s

SQL好,好。

+0

有趣,你能解釋一下如何添加GROUP BY修復它嗎? – cozos 2017-11-08 23:27:39

-1

最終查詢在相關子查詢中包含azienda_id,但您的初始查詢不包括核心子查詢中的azienda_id。所以比較是不一樣的。

+0

這應該是對linuxatico的答案的評論。 – jojonas 2016-09-08 10:47:41

-1

我已經通過比較'使用客戶統計'的數量測試了HLGEM的理論,結果表明不存在比搜索左表中所有記錄時的左連接快。

SQL的美妙之處在於它的寫作方式很多,性能並不完全取決於連接或子查詢,而是您正在尋找的結果集。