SQL效率:在子查询与JOIN中的位置然后是GROUP

时间:2009-07-24 18:04:26

标签: sql-server performance tsql

例如,我想获取应用了某些标签的所有项目的列表。我可以做以下任何一种情况:

SELECT Item.ID, Item.Name
FROM Item
WHERE Item.ID IN (
    SELECT ItemTag.ItemID
    FROM ItemTag
    WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55)

或者

SELECT Item.ID, Item.Name
FROM Item
LEFT JOIN ItemTag ON ItemTag.ItemID = Item.ID
WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55
GROUP BY Item.ID, Item.Name

或完全不同的东西。

一般来说(假设有一般规则),什么是更有效的方法?

7 个答案:

答案 0 :(得分:17)

SELECT Item.ID, Item.Name
FROM Item
WHERE Item.ID IN (
    SELECT ItemTag.ItemID
    FROM ItemTag
    WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55)
     

SELECT Item.ID, Item.Name
FROM Item
LEFT JOIN ItemTag ON ItemTag.ItemID = Item.ID
WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55
GROUP BY Item.ID

您的第二个查询将无法编译,因为它引用了Item.Name而没有对其进行分组或聚合。

如果我们从查询中删除GROUP BY

SELECT  Item.ID, Item.Name
FROM    Item
JOIN    ItemTag
ON      ItemTag.ItemID = Item.ID
WHERE   ItemTag.TagID = 57 OR ItemTag.TagID = 55

这些仍然是不同的查询,除非ItemTag.ItemIdUNIQUE密钥并标记为此类。

SQL Server能够检测IN列上的UNIQUE条件,并将IN条件转换为JOIN

如果ItemTag.ItemID不是UNIQUE,则第一个查询将使用一种SEMI JOIN算法,这种算法在SQL Server中非常有效。

您可以将第二个查询转换为JOIN

SELECT  Item.ID, Item.Name
FROM    Item
JOIN    (
        SELECT DISTINCT ItemID
        FROMT  ItemTag
        WHERE  ItemTag.TagID = 57 OR ItemTag.TagID = 55
        ) tags
ON      tags.ItemID = Item.ID

但是这个效率低于INEXISTS

在我的博客中查看此文章,以获得更详细的性能比较:

答案 1 :(得分:4)

我认为这取决于优化器如何处理它们,甚至可能是你最终获得相同性能的情况。显示执行计划是你的朋友。

答案 2 :(得分:2)

SELECT Item.ID, Item.Name
...
GROUP BY Item.ID

这不是有效的T-SQL。 Item.Name必须出现在group by子句中或聚合函数中,例如SUM或MAX。

答案 3 :(得分:1)

几乎不可能(除非你是那些疯狂的大师DBA之一)在不查看执行计划和/或运行压力测试的情况下告诉什么是快速的,什么是不会。

答案 4 :(得分:0)

运行这个:

SET SHOWPLAN_ALL ON

然后运行查询的每个版本

您可以看到他们是否返回相同的计划,如果没有查看每个计划的第一行的TotalSubtreeCost,看看它们有多么不同。

答案 5 :(得分:0)

性能似乎总是得到投票,但你也听到“购买硬件比程序员更便宜”

第二场胜利表现。

有时看看SQL并了解其目的很好,但这就是评论的用途。第一个查询是使用另一个表进行过滤 - 非常简单。

第二个使用distinct而不是group by更有意义(从理解目的而非性能)。我希望有些聚合在select中,但是没有。速度杀死。

答案 6 :(得分:0)

第二个在MySQL中效率更高。对于每个WHERE条件测试,MySQL都会在IN语句中重新执行查询。