在from子句或where子句中进行equi连接是否更好?

时间:2011-01-14 17:59:05

标签: sql sql-server sql-server-2005 tsql

在主键列上连接两个简单表并放置一个加法相等条件时,可以在join本身或where子句中完成。

例如以下是等价的。 我的问题是 - 有没有理由使用另一种风格?

SELECT * 
FROM A
INNER JOIN B ON A.A_ID = B.A_ID
            AND A.DURATION = 3.00

... VS:

SELECT * 
FROM A
INNER JOIN B ON A.A_ID = B.A_ID
WHERE A.DURATION = 3.00

6 个答案:

答案 0 :(得分:10)

一般来说,它没有语义差异。

虽然可以做一个边缘情况。如果将(已弃用的)GROUP BY ALL构造添加到查询中,如下所示。

DECLARE @A TABLE(A_ID INT, DURATION DECIMAL(3,2) )
INSERT INTO @A VALUES(1,2.00)

DECLARE @B TABLE(A_ID INT)
INSERT INTO @B VALUES(1)

/*Returns one row*/
SELECT *
FROM @A A
INNER JOIN @B B ON A.A_ID = B.A_ID
WHERE A.DURATION = 3.00
GROUP BY ALL A.A_ID, A.DURATION, B.A_ID

/*Returns zero rows*/    
SELECT *
FROM @A A
INNER JOIN @B B ON A.A_ID = B.A_ID  AND A.DURATION = 3.00
GROUP BY ALL A.A_ID, A.DURATION, B.A_ID

答案 1 :(得分:9)

这是一种风格问题。通常,您希望在FROM子句中放置定义结果集“形状”的条件(即控制每个表中的哪些行应该连接在一起以生成结果的条件),而那些条件 filter 结果集应该在WHERE子句中。对于INNER JOIN,效果相同,但一旦涉及OUTER JOIN(LEFT,RIGHT),感觉就会更加清晰。


在你的第一个例子中,我还在问“这与表B有什么关系?”当我在JOIN中遇到这种奇怪的情况时。在第二个中,如果我不感兴趣,我可以跳过FROM子句(以及所有JOIN),并且只看到确定是否将在WHERE子句中返回行的条件。

答案 2 :(得分:6)

重要的是JOIN的类型 没有区别,所提供的查询版本都将使用相同的执行计划,因为您正在处理INNER JOIN。

如果处理OUTER JOIN(IE:LEFT,RIGHT),两个版本之间存在 巨大的 差异,因为应用了WHERE条件之后进行JOIN。如果在ON子句中指定了条件,则在 JOIN之前应用标准,这可能会在结果集之间产生相当大的差异。

答案 3 :(得分:3)

对于SQL Server 2000+,每个查询的查询计划都是不确定的,因此性能也是如此。

您可以使用SSMS验证这一点,以便在执行查询之前显示每个点击CTRL + M的查询的实际执行计划。结果窗格将有一个附加选项卡,显示执行计划。你会看到,在这种情况下,两个计划是相同的。

答案 4 :(得分:1)

这是一种风格问题。优化器将做到最好。

答案 5 :(得分:0)

    --Samples for time of join wheather can we write condition at where or ON 
create table #emp(id int ,teamid int)
create table #team(tid int,name char(2))
insert into #emp values(1,1)
insert into #emp values(2,1)
insert into #emp values(3,2)
insert into #emp values(4,0)

insert into #team values(1,'A')
insert into #team values(2,'B')
insert into #team values(3,'C')

--select * from #emp
--select * from #team

--on inner join => there is no difference in Query Exc. Plan
--select * from #emp e join #team t on e.teamid=t.tid where e.teamid=2
--select * from #emp e join #team t on e.teamid=t.tid and e.teamid=2


/*on outetr join see the differnence If dealing with an OUTER JOIN (IE: LEFT, RIGHT), 
there is a huge difference between the two versions because the WHERE criteria is applied after the JOIN is made. 
If the criteria is specified in the ON clause, the criteria is applied before the JOIN is made which can made a considerable difference 
between the result sets.*/
select * from #emp e left join #team t on e.teamid=t.tid
select * from #emp e left join #team t on e.teamid=t.tid where e.teamid=2
select * from #emp e left join #team t on e.teamid=t.tid and  (e.teamid=2 or t.tid=1) and t.name='A'


drop table #emp
drop table #team