Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server SQL效率:在子查询与连接中的位置,然后是组_Sql Server_Performance_Tsql - Fatal编程技术网

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