2012-02-13 104 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