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

Lar*_*nal 16 t-sql sql-server performance

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

SELECT Item.ID, Item.Name
FROM Item
WHERE Item.ID IN (
    SELECT ItemTag.ItemID
    FROM ItemTag
    WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55)
Run Code Online (Sandbox Code Playgroud)

要么

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
Run Code Online (Sandbox Code Playgroud)

或者完全不同的东西.

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

Qua*_*noi 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)
Run Code Online (Sandbox Code Playgroud)

要么

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
Run Code Online (Sandbox Code Playgroud)

您的第二个查询将无法编译,因为它引用时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
Run Code Online (Sandbox Code Playgroud)

这些仍然是不同的查询,除非ItemTag.ItemId是一个UNIQUE密钥并标记为这样.

SQL Server能够检测列IN上的条件UNIQUE,并将IN条件转换为a 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
Run Code Online (Sandbox Code Playgroud)

但是这个比INor 更低效EXISTS.

请参阅我的博客中的这篇文章,以获得更详细的性能比较: