为什么左连接导致NEWID()比加入更快实现?

时间:2014-09-25 17:57:15

标签: sql sql-server tsql

使用MSSQL Server 2008企业版,很可能是其他版本的MSSQL,这里有一个概念证明,它使得临时表和具体化的NEWID()取决于你是否使用了JOIN或LEFT JOIN,即使我们是完全匹配两行。

如果查看执行计划,可以看到使用JOIN最后执行获取NEWID()的计算标量,但在使用LEFT JOIN时则不会。我原本期望LEFT JOIN行为。这种怪异是由于执行计划中的天真还是还有更多的事情发生?

使用临时表进行演示:

Create Table #Temp
(
    ChildGuid uniqueidentifier,
    ParentGuid uniqueidentifier
)
insert into #Temp (ChildGuid, ParentGuid) Values('5E3211E8-D382-4775-8F96-041BF419E70F', '96031FA0-829F-43A1-B5A6-108362A37701')
insert into #Temp (ChildGuid, ParentGuid) Values('FFFFFFFF-D382-4775-8F96-041BF419E70F', '96031FA0-829F-43A1-B5A6-108362A37701')

--Use a join. Get different NewIDs.
select * from #Temp 
join 
(
    select ParentGuid, NewParentGuid from(
    select ParentGuid, NEWID() as NewParentGuid from #Temp
    group by ParentGuid
    ) tb2
) temp2 on #Temp.ParentGuid = temp2.ParentGuid

--Do exactly as above, but use a left join. Get a pair of the same NewIDs.
select * from #Temp 
left join 
(
    select ParentGuid, NewParentGuid from(
    select ParentGuid, NEWID() as NewParentGuid from #Temp
    group by ParentGuid
    ) tb2
) temp2 on #Temp.ParentGuid = temp2.ParentGuid

使用Join,NewParentGuid对于两行都不同。

使用Left Join,NewParentGuid是相同的。

EDIT2:如果您将此附加到左侧联接,则结果会更改。

where temp2.ParentGuid = temp2.ParentGuid

或者正如另一位用户指出的那样,该列不为null。在对其他列进行比较时,或者在1 = 1.Schroedinger的列中,它们将保持不变?

另见:

Why does newid() materialize at the very end of a query?

2 个答案:

答案 0 :(得分:1)

不是答案,而是观察

这会返回重复的

select * from #Temp 
inner hash join 
(
     select ParentGuid, NEWID() as NewParentGuid 
     from #Temp
     group by ParentGuid
     union 
     select null, NEWID()    
) temp2 
  on #Temp.ParentGuid = temp2.ParentGuid

--Do exactly as above, but use a left join. Get a pair of the same NewIDs.
select * from #Temp 
left hash join 
(
     select ParentGuid, NEWID() as NewParentGuid 
     from #Temp
     group by ParentGuid
) temp2 
  on #Temp.ParentGuid = temp2.ParentGuid

这迫使他们两者不同

select * from #Temp  join  (
     select ParentGuid, NEWID() as NewParentGuid 
     from #Temp
     group by ParentGuid    ) temp2 
     on #Temp.ParentGuid = temp2.ParentGuid

--Do exactly as above, but use a left join. Get a pair of the same NewIDs. select * from #Temp  left  join  (
     select ParentGuid, NEWID() as NewParentGuid 
     from #Temp
     group by ParentGuid ) temp2 
     on #Temp.ParentGuid = temp2.ParentGuid 
    and temp2.ParentGuid is not null

答案 1 :(得分:0)

我不知道为什么它在内部连接的查询结束时实现了,但是如果你像这样放置一个where子句,那么左连接aslo的行为就会改变(有效地将它改为内部加入)

select * from #Temp 
left join 
(
    select ParentGuid, NewParentGuid from(
    select ParentGuid, NEWID() as NewParentGuid from #Temp
    group by ParentGuid
    ) tb2
) temp2 on #Temp.ParentGuid = temp2.ParentGuid
where temp2.ParentGuid is not null

对于任何where子句,它可能会这样做。嗯,似乎你希望GUID在上面的左连接条件中按预期工作,最安全的做法是完全选择外部的派生表并将结果放入临时表。然后维护不会意外地改变它的工作方式。