有条件的加入

时间:2013-07-25 18:59:52

标签: sql sql-server

我正在尝试像这样实现条件连接

declare @JoinWithT2 bit = 1;

select T1.* from T1 
inner join T2 on (@JoinWithT2 = 0 or T1.Id=T2.Id)

这很好,当我传递@JoinWithT2值1时,它使用两个表的连接给我结果,当我传递@JoinWithT2值0时,它返回T1的所有结果,忽略连接

这一切都运作良好,但我担心性能,因为上述也可以像这样实现

if @JoinWithT2=0
begin
    select T1.* from T1 
end
else
begin
    select T1.* from T1 
    inner join T2 on (T1.Id=T2.Id)
end

实现条件连接的最佳方法是什么,第一个或第二个?

我个人认为第二个应该更好的表现,因为它根本不涉及T2而第一个查询可能正在使用T2

4 个答案:

答案 0 :(得分:2)

我很困惑。以下应该是笛卡尔积或内连接,具体取决于JoinWithT2

的值
declare @JoinWithT2 bit = 1;

select T1.*
from T1 inner join
     T2
     on (@JoinWithT2 = 0 or T1.Id=T2.Id);

@JoinWithT20时,on子句始终为true。这使得join相当于cross join

以下是进行连接或获取第一个表的条件逻辑:

declare @JoinWithT2 bit = 1;

select T1.*
from T1 left outer join
     T2
     on (@JoinWithT2 = 1 and T1.Id=T2.Id)
where @JoinWithT2 = 0 or T2.Id is not null;

从性能角度来看,if中的单独语句通常会表现得更好。 SQL引擎有更多信息可供优化。但是,如果您在T2(id)上有索引,那么相对于查询的其他部分,性能差异可能不会很大,例如将结果返回给用户。

答案 1 :(得分:1)

在这种情况下,最好的选择可能是动态SQL,或者在较新版本的SQL服务器中条件不如旧版本那么糟糕。 if语句很好但在添加两个或三个其他表之后很难维护,这些表可能会或可能不会根据特定条件加入。随着时间的推移,或者条件可能会变慢,并且会向查询添加更多内容。仅使用此特定参数集所需的内容构建搜索类型查询通常是最佳选择。

您可能需要阅读:

http://www.sommarskog.se/dyn-search-2008.html

或(如果您使用SQL SERVER 2005或更早版本) http://www.sommarskog.se/dyn-search-2005.html

答案 2 :(得分:1)

如果您不从T2中选择任何内容,为什么还需要加入?同样可以通过以下方式实现:

select T1.*
from T1 
where @JoinWithT2 = 0 or T1.Id in (select T2.Id from T2);

答案 3 :(得分:1)

静态解决方案:

CREATE VIEW Person.vBusinessEntityAddressWithInfo
AS
SELECT  bea.AddressID,bea.AddressTypeID,bea.BusinessEntityID,bea.ModifiedDate,
        a.PostalCode AS AddressPostalCode,a.City AS AddressPostalCity
FROM    Person.BusinessEntityAddress bea
JOIN    Person.[Address] a ON bea.AddressID=a.AddressID;
GO
-- Test #1: columns from only one table Person.BusinessEntityAddress
SELECT  v.AddressID,v.BusinessEntityID
FROM    Person.vBusinessEntityAddressWithInfo v
GO
-- Test #2: columns from both tables
SELECT  v.AddressID,v.BusinessEntityID,v.AddressPostalCode
FROM    Person.vBusinessEntityAddressWithInfo v
GO

如果我查看执行计划,那么我可以看到Test #1 SQL Server仅使用Person.BusinessEntityAddress表(请参阅FK elimination;另请参阅此answer)以及Test #2 SQL Server使用两个表: enter image description here

另一个“静态”(或多或少)解决方案:

DECLARE @Type BIT;
SET     @Type=0;

SELECT  bea.*,NULL AS AddressPostalCode,NULL AS AddressPostalCity
FROM    Person.BusinessEntityAddress bea
WHERE   @Type=0
UNION ALL
SELECT  bea.*,a.PostalCode AS AddressPostalCode,a.City AS AddressPostalCity
FROM    Person.BusinessEntityAddress bea
JOIN    Person.[Address] a ON bea.AddressID=a.AddressID
WHERE   @Type=1;

如果我使用@Type=0SET STATISTICS IO ON执行此查询,则SQL Server将从BusinessEntityAddress读取数据:

Table 'Worktable'. Scan count 0, logical reads 0
Table 'Worktable'. Scan count 0, logical reads 0
Table 'BusinessEntityAddress'. Scan count 1, logical reads 112

当我用@Type=1执行相同的查询时,SQL Server将从两个表中读取数据:

Table 'Worktable'. Scan count 0, logical reads 0
Table 'Address'. Scan count 1, logical reads 216
Table 'BusinessEntityAddress'. Scan count 1, logical reads 112
Table 'Worktable'. Scan count 0, logical reads 0