2010-07-01 84 views
9

假設我們有兩個表格:'Car'和'Part',並在'Car_Part'中加入一個表格。假設我想查看其中有123部分的所有汽車。我可以這樣做:哪一個更快:加入GROUP BY或子查詢?

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
INNER JOIN Car_Part ON Car_Part.Car_Id = Car.Car_Id 
WHERE Car_Part.Part_Id = @part_to_look_for 
GROUP BY Car.Col1, Car.Col2, Car.Col3 

或者我能做到這一點

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
WHERE Car.Car_Id IN (SELECT Car_Id FROM Car_Part WHERE Part_Id = @part_to_look_for) 

現在,一切都在我想用第一種方法,因爲我一直好父母誰在我灌輸長大清教徒對子查詢的憎恨和對集合論的熱愛,但是有人向我建議,做這麼大的GROUP BY比子查詢更糟糕。

我應該指出,我們在SQL Server 2008上。我也應該說,實際上我想根據零件ID,零件類型和其他可能的情況來選擇。所以,我想真正做的查詢看起來是這樣的:

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
INNER JOIN Car_Part ON Car_Part.Car_Id = Car.Car_Id 
INNER JOIN Part ON Part.Part_Id = Car_Part.Part_Id 
WHERE (@part_Id IS NULL OR Car_Part.Part_Id = @part_Id) 
AND (@part_type IS NULL OR Part.Part_Type = @part_type) 
GROUP BY Car.Col1, Car.Col2, Car.Col3 

或者......

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
WHERE (@part_Id IS NULL OR Car.Car_Id IN (
    SELECT Car_Id 
    FROM Car_Part 
    WHERE Part_Id = @part_Id)) 
AND (@part_type IS NULL OR Car.Car_Id IN (
    SELECT Car_Id 
    FROM Car_Part 
    INNER JOIN Part ON Part.Part_Id = Car_Part.Part_Id 
    WHERE Part.Part_Type = @part_type)) 
+2

你跑了嗎?看着查詢計劃?基準? – Oded 2010-07-01 08:27:58

+1

我不得不生成大量的數據,所以我不會在下個星期之前瞭解它。當我搜索答案時,我沒有找到答案,所以值得在網上發佈一個可能正在尋找的人的問題。 – d4nt 2010-07-01 08:31:00

+0

Group By是勞動密集型的,用於計算像平均數,總和等東西。您似乎使用它來消除重複項。嘗試DISTINCT沒有羣組... – Alocyte 2017-11-23 14:14:27

回答

3

我有類似的數據,所以我檢查了這兩種查詢風格的執行計劃。令我驚訝的是,在子查詢中的列(CIS)產生了一個執行計劃,比內部連接(IJ)查詢少25%的I/O開銷。在CIS執行計劃中,我得到了中間表(Car_Part)的2個索引掃描與中間索引掃描,以及IJ中相對更昂貴的散列連接。我的索引是健康的,但是非聚集的,所以有理由認爲索引掃描可能會通過聚集它們而變得更快一些。我懷疑這會影響散列連接的成本,這是IJ查詢中更昂貴的步驟。

像其他人一樣指出,這取決於您的數據。如果你在這3個表中使用了很多千兆字節,然後調離。 如果你的行數以數百或數千計數,那麼你可能會以非常小的性能增益分割毛髮。我會說IJ查詢的可讀性要好得多,只要它足夠好,可以做任何未來的開發人員,他們會幫助您更好地閱讀代碼併爲其提供便利。我的表中的行數是188877,283912,13054,並且兩個查詢都返回的時間更短,以至於只能喝咖啡。

小postscript:因爲你不彙總任何數值,它看起來像你的意思是選擇不同。除非你真的要對這個小組做些什麼,否則最後你會更容易看到你的意圖是選擇不同的而不是小組。IO成本是相同的,但一個表明你的意圖更好恕我直言。

4

你能做的最好的事情是自己進行測試,在現實的數據量。這不僅有利於這個查詢,而且對於所有未來的查詢,當你不確定哪個是最好的方法時。

重要的事情要做包括:
- 生產級數據量的測試
- 測試相當&一致(清除緩存:http://www.adathedev.co.uk/2010/02/would-you-like-sql-cache-with-that.html
- 你既可以使用SQL事件探查監控檢查執行計劃

並檢查持續時間/讀取/寫入/ CPU,或SET STATISTICS IO ON; SET STATISTICS TIME ON;在SSMS中輸出統計信息。然後比較每個查詢的統計信息。

如果你不能做這種類型的測試,你可能會暴露自己的性能問題,你必須調整/糾正。你可以使用那些可以爲你生成數據的工具。

2

有了SQL Server 2008我希望In要快,因爲它等同於這一點。

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
WHERE EXISTS(SELECT * FROM Car_Part 
      WHERE Car_Part.Car_Id = Car.Car_Id 
      AND Car_Part.Part_Id = @part_to_look_for 
) 

即它只需要檢查行的存在不加入它然後刪除重複。這是discussed here