SQL 效率:WHERE IN 子查询与 JOIN 然后 GROUP
Posted
技术标签:
【中文标题】SQL 效率:WHERE IN 子查询与 JOIN 然后 GROUP【英文标题】:SQL Efficiency: WHERE IN Subquery vs. JOIN then GROUP 【发布时间】:2010-11-13 20:01:26 【问题描述】:例如,我想获取应用了特定标签的所有项目的列表。我可以执行以下任一操作:
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
或者完全不同的东西。
一般来说(假设有一个通用规则),什么是更有效的方法?
【问题讨论】:
@Larsenal:您可以在第二个查询中将LEFT JOIN
替换为INNER JOIN
,结果将是相同的。对于ItemTag
中没有对应Item.ID
的行,LEFT JOIN
将返回NULL
s,而您的WHERE
条件会将它们过滤掉。
【参考方案1】:
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.ItemId
是 UNIQUE
键并标记为这样。
SQL Server
能够检测到UNIQUE
列上的IN
条件,并且只会将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
但是这个效率比IN
或EXISTS
低一点。
有关更详细的性能比较,请参阅我的博客中的这篇文章:
IN
vs. JOIN
vs. EXISTS
【讨论】:
【参考方案2】:我认为这将取决于优化器如何处理它们,甚至可能最终获得相同的性能。在这里显示执行计划是你的朋友。
【讨论】:
【参考方案3】:SELECT Item.ID, Item.Name
...
GROUP BY Item.ID
这不是有效的 T-SQL。 Item.Name 必须出现在 group by 子句或聚合函数中,例如 SUM 或 MAX。
【讨论】:
【参考方案4】:如果不查看执行计划和/或运行一些压力测试,几乎不可能(除非您是那些疯狂的 DBA 大师之一)来判断什么会很快,什么不会。
【讨论】:
其实很容易说:第二个要快得多。它只会拒绝在一纳秒左右的时间内编译。 @Quassnoi 这不会让它变慢吗?返回结果需要无限的时间......【参考方案5】:运行这个:
SET SHOWPLAN_ALL ON
然后运行每个版本的查询
您可以查看它们是否返回相同的计划,如果不是,请查看每个计划第一行的 TotalSubtreeCost 并了解它们的不同之处。
【讨论】:
【参考方案6】:性能似乎总能赢得选票,但你也听说“买硬件比程序员便宜”
第二个在性能上获胜。
有时查看 SQL 并了解其用途是件好事,但这就是 cmets 的用途。第一个查询使用另一个表作为过滤器 - 非常简单。
第二个使用 distinct 而不是 group by 会更有意义(从理解目的而不是性能)。我希望一些聚合会在选择中,但没有。速度杀人。
【讨论】:
【参考方案7】:第二个在 mysql 中效率更高。对于每个 WHERE 条件测试,MySQL 都会在 IN 语句中重新执行查询。
【讨论】:
以上是关于SQL 效率:WHERE IN 子查询与 JOIN 然后 GROUP的主要内容,如果未能解决你的问题,请参考以下文章
为啥 MySQL JOIN 比 WHERE IN (子查询) 快得多
sql中where的与jnner join on的连接条件.哪个优先级别高?
MySql子查询(wherefromexists)及连接查询(left joinright joininner joinunion join)
sql中in和exist语句的区别?(补充了left join和right join)