多个LEFT JOIN性能问题的聚合(SQL SERVER)

时间:2012-02-13 10:12:33

标签: sql-server performance aggregation

关于运行超过30分钟的非常简单的查询,我遇到了性能问题:

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

每个查询在几毫秒内回复的位置:

离。

  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将是:

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

[编辑]感谢social.msdn.microsoft.com上的 Erland Sommarskog ,指出了我的分析错误。 - 有关答案的详细信息

请记住:
LEFT JOIN形成笛卡尔积

我错了,假设笛卡尔积可能已被过滤,因为我总是引用同一张表。

感谢

2 个答案:

答案 0 :(得分:3)

也许是这样的:

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 

答案 1 :(得分: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(*)之外的其他聚合,而不必运行更多相关子查询,这将非常有用。