我最近发现使用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。
有人可以解释对此案的隐含评价吗?
答案 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;
如果使用提示,则为第二:
当您将此查询提示添加到查询中时,它会告诉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);
你会得到:
答案 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
的