Sql server SQL效率:在子查询与连接中的位置,然后是组
作为一个例子,我想得到应用了特定标记的所有项目的列表。我可以执行以下任一操作:Sql server SQL效率:在子查询与连接中的位置,然后是组,sql-server,performance,tsql,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
WHERE Item.ID IN (
SELECT ItemTag.ItemID
FROM ItemTag
WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55)
或
或者完全不同的东西
一般来说(假设有一个通用规则),什么是更有效的方法?我认为这将取决于优化器如何处理它们,甚至可能最终获得相同的性能。“显示执行计划”是您的朋友。如果不查看执行计划和/或运行一些压力测试,就很难判断什么会快,什么不会快(除非您是那些疯狂的DBA大师之一)
SELECT Item.ID, Item.Name
...
GROUP BY Item.ID
这是无效的T-SQL。Item.Name必须出现在group by子句中或聚合函数中,如SUM或MAX。运行以下命令:
SET SHOWPLAN_ALL ON
然后运行查询的每个版本
您可以查看它们是否返回相同的计划,如果不返回,请查看每个计划第一行的TotalSubtreeCost,并查看它们之间的差异
或
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
,而没有对其进行分组或聚合
如果我们从查询中删除分组依据
:
SELECT Item.ID, Item.Name
FROM Item
JOIN ItemTag
ON ItemTag.ItemID = Item.ID
WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55
这些仍然是不同的查询,除非ItemTag.ItemId
是一个唯一的
键,并被标记为这样
SQL Server
能够在UNIQUE
列上检测到IN
条件,并将IN
条件转换为连接
如果ItemTag.ItemID
不是唯一的
,则第一个查询将使用一种半联接
算法,这在SQL Server
中非常有效
您可以将第二个查询转换为联接
:
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
但是这一个的效率比中的或存在的要低一些
有关更详细的性能比较,请参阅我博客中的这篇文章:
性能似乎总能赢得选票,但你也会听到“购买硬件比程序员便宜”
第二个以表现取胜
有时,了解SQL并了解其用途是很好的,但这就是注释的用途。第一个查询使用另一个表作为过滤器-非常直接
第二种方法(出于理解目的而非绩效)使用distinct而不是group by更有意义。我希望select中会有一些聚合,但没有。速度致命。第二个在MySQL中效率更高。MySQL将在IN语句中为每个WHERE条件测试重新执行查询。事实上,很容易说:第二个要快得多。它只会在一纳秒左右的时间内拒绝编译。@Quassnoi这不会让它变得更慢吗?返回结果需要无限长的时间…@Larsenal:您可以在第二次查询中将左连接
替换为内部连接
,结果将是相同的。LEFT JOIN
将为ItemTag
中没有相应Item.ID
的行返回NULL
s,您的WHERE
条件将过滤掉它们。
SELECT Item.ID, Item.Name
FROM Item
JOIN ItemTag
ON ItemTag.ItemID = Item.ID
WHERE ItemTag.TagID = 57 OR ItemTag.TagID = 55
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