tsql中奇怪的连接行为

tsql中奇怪的连接行为,sql,sql-server,tsql,join,sql-execution-plan,Sql,Sql Server,Tsql,Join,Sql Execution Plan,我最近发现了使用JOIN-ON而不是更熟悉的JOIN-ON-JOIN-ON语法的旧代码 DECLARE @a TABLE ( val INT ) DECLARE @b TABLE ( val INT ) DECLARE @c TABLE ( val INT ) INSERT INTO @a VALUES (1),(2),(4) INSERT INTO @b VALUES (1),(2),(4) INSERT INTO @c VALUES (1),(2),(4) S

我最近发现了使用JOIN-ON而不是更熟悉的JOIN-ON-JOIN-ON语法的旧代码

DECLARE @a TABLE (
    val INT
)
DECLARE @b TABLE (
    val INT
)
DECLARE @c TABLE (
    val INT
)


INSERT INTO @a VALUES (1),(2),(4)
INSERT INTO @b VALUES (1),(2),(4)
INSERT INTO @c VALUES (1),(2),(4)


SELECT *
FROM @a as a
join @b as b 
join @c as c
    on b.val = c.val    on a.val = b.val
我现在觉得奇怪的是,如果你查阅查询计划,首先a和c是连接的,但甚至没有连接条件a.val=c.val

有人能解释这个案例的隐含评价吗


我认为这是查询优化器的事情。首先,请回答您的问题:

SELECT *
FROM @a as a
join @b as b 
join @c as c
    on b.val = c.val
    on a.val = b.val;
同:

SELECT *
FROM @a AS A
JOIN ( @b AS B 
       JOIN @c AS C ON B.Val = C.Val
)  ON   A.Val = B.Val;
第二,如果您使用提示:

当您将此查询提示添加到查询中时,它会告诉SQL Server在执行语句时不要更改查询中联接的顺序。它将按照查询中指定的确切顺序联接表

通常,SQL Server优化器会按照其认为对查询执行最有利的顺序重新排列联接

您将获得:

自从您加入后:

  • @a
    @b
  • @b
    @c
在同一个
b.val
列上,如果您将这两个表连接在一起(在
a.val
=
c.val
),然后将
@b
中的所有内容放入最终结果集中,则效果相当(而且性能更好)

@a
@c
之间的联接条件不是显式的,而是隐式的


其他杂项信息:

此外,由于您要连接表变量,因此执行计划中每个迭代器的行估计值(表扫描
@a
@b
@c
)很可能为1

因此,有了这些信息,SQL Server很可能会认为没有理由以任何特定顺序加入
1行
表。因此,在一些执行中,您可以在执行计划的底部分支中加入
@a
@b
,在其他执行中,您可以获得
@a
@c


但这只是猜测,可以肯定的是连接条件是隐式的,而不是显式的,这就是为什么要先连接
@a
@c

感谢您指出这一点。最后,查询优化让我更加困惑。使用强制顺序更有意义。我仍然认为这是一种糟糕的风格:)我不会真正使用
FORCE-ORDER
,除非我100%确信优化器不会自行发现以书面顺序进行连接更有效。@RaduGheorghiu-FORCE-ORDER是为了说明思考连接的OP方式。这里查询优化器使用不同的顺序,这是误导性的(但仍然正确,因为a=b和b=c=>a=c)@lad2025同意,我没意见:)@lad2025指出,这只是为了可视化发生了什么。当然,我知道我的条件是隐式的,查询优化器完成了它的工作。这让我非常困惑:)
SELECT *
FROM @a as a
join @b as b 
join @c as c
    on b.val = c.val
    on a.val = b.val  
    OPTION (FORCE ORDER);