2012-02-13 105 views
1

我有一個關於對於超過30分鐘,運行一個很簡單的查詢性能問題:聚集JOIN性能問題(SQL SERVER)

SELECT P.pID 
    ,COUNT(T1.ID) AS NB1 
    ,COUNT(T2.ID) AS NB2 
    ,COUNT(T3.ID) AS NB3 
    ,COUNT(T4.ID) AS NB4 
    ,COUNT(T5.ID) AS NB5 

FROM MainTable P 

LEFT OUTER JOIN Table1 T1 ON P.pID = T1.pID 
LEFT OUTER JOIN Table2 T2 ON P.pID = T2.pID 
LEFT OUTER JOIN Table3 T3 ON P.pID = T3.pID 
LEFT OUTER JOIN Table4 T4 ON P.pID = T4.pID 
LEFT OUTER JOIN Table5 T5 ON P.pID = T5.pID 

GROUP BY P.pID 

凡爲每個查詢會在幾毫秒回覆:

ex。

SELECT P.pID 
     ,COUNT(T1.ID) AS NB1 

    FROM MainTable P 
    LEFT OUTER JOIN Table1 T1 ON P.pID = T1.pID 

    GROUP BY P.pID 

如果我不使用任何聚合(COUNT或其他任何東西)查詢運行在幾毫秒: 前。 SELECT P.pID

FROM MainTable P 

LEFT OUTER JOIN Table1 T1 ON P.pID = T1.pID 
LEFT OUTER JOIN Table2 T2 ON P.pID = T2.pID 
LEFT OUTER JOIN Table3 T3 ON P.pID = T3.pID 
LEFT OUTER JOIN Table4 T4 ON P.pID = T4.pID 
LEFT OUTER JOIN Table5 T5 ON P.pID = T5.pID 

GROUP BY P.pID 

顯然,所有指標都設置等等 唯一的「放緩」元素是pid是一個varchar(50),但我不能改變它,在我看來這這裏不是主要問題。

我使用了一個解決方法,包括所有工作正常的工會,但我真的想知道爲什麼這些是如此之久,我怎麼可以優化這一點作爲聚合多個左連接是真正常見的報告項目的東西,不應該這麼慢。

謝謝你的幫助。

[編輯] thx到ARION我有一個很好的查詢工作真的很好。

但我主要關心的是瞭解在用多個左連接編寫查詢的sql引擎中出現了什麼問題。

表DESCR是:在social.msdn.microsoft.com

Table P (500 rows) 
pID varchar(50) NOT NULL as primary key 
p.* doesn't matter 

Table Tn (between 2000 and 8000 rows) 
Tn.ID int NOT NULL as primary key 
pID varchar(50) NOT NULL as Foreign key 

[編輯]由於厄蘭Sommarskog指向我,我的分析誤差。 - 詳細介紹一下答案

請記住:
LEFT JOIN表笛卡爾乘積

我錯了假設笛卡爾乘積可能已被過濾,因爲我總是參考,以相同的表。

感謝

+0

我們需要查看一些數據樣本和表格統計信息 – cctan 2012-02-13 10:23:50

+0

原始查詢的問題不是(僅)緩慢。如果'Tx'表中的行具有普通的'pID',它也可能給出錯誤的結果。 – 2012-02-13 14:46:26

回答

2

也許是這樣的:

SELECT 
    P.pID, 
    (SELECT COUNT(*) FROM Table1 T1 WHERE P.pID = T1.pID) AS NB1, 
    (SELECT COUNT(*) FROM Table2 T2 WHERE P.pID = T2.pID) AS NB2, 
    (SELECT COUNT(*) FROM Table3 T3 WHERE P.pID = T3.pID) AS NB3, 
    (SELECT COUNT(*) FROM Table4 T4 WHERE P.pID = T4.pID) AS NB4, 
    (SELECT COUNT(*) FROM Table5 T5 WHERE P.pID = T5.pID) AS NB5 

FROM MainTable P 
+0

嗨,感謝Arion這件作品。 我仍然想知道爲什麼查詢太慢。 你有什麼想法嗎? – Kilren 2012-02-13 10:36:17

+0

好吧,我可能無論如何,我的主要關注點是瞭解sql引擎編寫多個左連接查詢時出了什麼問題。這就是爲什麼我會保持它開放一點,除非你有我的答案。 – Kilren 2012-02-13 10:50:56

+0

好的。對於那個很抱歉。我認爲這是因爲你正在使用一個varchar計數,然後加入它,然後再對它進行分組。你需要更多的時間做這項工作。您正在處理更多數據,然後您將實際使用不必要的連接。如果你只是對計數感興趣,這是更好的解決方案。 – Arion 2012-02-13 11:01:30

1

您還可以通過改寫由第一組查詢(子查詢),然後加入:

SELECT 
    P.pID, 
    T1.NB1, 
    T2.NB2, 
    T3.NB3, 
    T4.NB4, 
    T5.NB5 
FROM MainTable P 
    LEFT JOIN 
    (SELECT pID, COUNT(*) AS NB1 FROM Table1 GROUP BY pID) AS T1 
    ON T1.pID = P.pID 
    LEFT JOIN 
    (SELECT pID, COUNT(*) AS NB2 FROM Table2 GROUP BY pID) AS T2 
    ON T2.pID = P.pID 
    LEFT JOIN 
    (SELECT pID, COUNT(*) AS NB3 FROM Table3 GROUP BY pID) AS T3 
    ON T3.pID = P.pID 
    LEFT JOIN 
    (SELECT pID, COUNT(*) AS NB4 FROM Table4 GROUP BY pID) AS T4 
    ON T4.pID = P.pID 
    LEFT JOIN 
    (SELECT pID, COUNT(*) AS NB5 FROM Table5 GROUP BY pID) AS T5 
    ON T5.pID = P.pID 

這將是有益的如果您想在結果中包含其他聚合,除了COUNT(*)之外,無需運行更多相關的子查詢。

+0

順便說一句,使用其他聚合函數(如總和)與** Arion **解決方案一起工作 – Kilren 2012-02-13 14:57:13

+0

它的工作原理,但你必須在'SELECT'列表中添加另一個子查詢。我不確定SQL-Server是否會正確地優化它(僅爲COUNT和SUM運行一個子查詢)。 – 2012-02-13 14:59:52