为什么优化器在这里选择嵌套循环而不是合并连接?

Gri*_*rim 5 join sql-server optimization database-internals

我有3张桌子。#a是一个主表和两个辅助表,#b并且#c.

create table #a (a int not null, primary key (a asc)) ;
create table #b (b int not null, primary key (b asc)) ;
create table #c (c int not null, primary key (c asc)) ;

insert into #a (a)
select x*10 + y
from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))x(x)
cross join (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))y(y) ;

insert into #b (b)
select a from #a where a % 5 > 0 ;

insert into #c (c)
select a from #a where a % 4 > 0 ;
Run Code Online (Sandbox Code Playgroud)

如果我只将主表#a与一个辅助表连接,则查询计划中将有合并连接。

select *
from #a a
inner join #b b on a = b ;
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

但是,如果我将主表#a与两个辅助表连接起来,则只会有嵌套循环。

select *
from #a a
inner join #b b on a = b
inner join #c c on a = c ;
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

为什么它会这样工作,我应该怎么做才能获得两个合并连接?

没有inner merge join提示。

Pau*_*ite 7

为什么它会这样工作,我应该怎么做才能获得两个合并连接?

通过三个表引用(最低要求),查询符合基于成本优化的事务处理(又名搜索 0)阶段。

此阶段针对 OLTP 查询,它通常受益​​于导航(基于索引)策略。嵌套循环连接是可用的主要物理连接类型(只有在此阶段找不到有效的嵌套循环计划时才考虑散列和合并)。

如果这个阶段找到一个低成本(足够好)的计划,基于成本的优化就会停止。这可以防止在优化上花费更多时间,而我们可以期望节省迄今为止找到的最佳解决方案。如果成本超过阈值,优化器将进入快速计划(搜索 1)、并行快速计划完全优化(搜索 2)阶段。

带有两个表引用的查询不符合事务处理条件,直接进入Quick Plan,其中 Merge 和 Hash 联接可用。

有关更多信息,请参阅我的Query Optimizer Deep Dive系列。

没有inner merge join提示。

如果您绝对必须暗示物理连接类型,强烈建议使用OPTION (MERGE JOIN). 这允许优化器仍然考虑更改连接顺序。

连接提示如INNER MERGE JOIN带有隐含的OPTION (FORCE ORDER),这严重限制了优化器的自由,其后果大多数人(包括专家)不理解。