在tsql中奇怪地加入了行为

时间:2017-08-02 12:15:37

标签: sql sql-server tsql join sql-execution-plan

我最近发现使用JOIN JOIN ON 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。

有人可以解释对此案的隐含评价吗?

enter image description here

2 个答案:

答案 0 :(得分:4)

我会说这是查询优化器的事情。首先是您的查询:

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;

如果使用提示,则为第二:

  

FORCE ORDER

     

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

     

通常,SQL Server优化器会将您的连接重新排列为它认为最适合您的查询执行的顺序。

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);  

你会得到:

enter image description here

答案 1 :(得分:3)

自从你加入以来:

  • @a@b以及
  • @b@c
如果您只是将这两个表连接在一起(b.val = a.val上),那么

在同一c.val列上,它是等效的(并且具有更好的性能)来自最终结果集中@b的所有内容。

@a@c之间的联接条件不明确,但隐含。

其他杂项信息:

此外,由于您正在连接表变量,因此最有可能的行估计执行计划中的每个迭代器(@a@b@c)将为1。

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

但这只是所有推测,可以肯定的是,连接条件是隐含的,但不是明确的,这就是为什么你首先加入@a@c

相关问题