奇怪的加入 sql 中的行为
Weird join on on behavior in tsql
我最近发现旧代码使用 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.
任何人都可以解释这种情况下的隐式评估吗?
我会说这是查询优化器的事情。首先您的查询:
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;
第二,如果你使用提示:
When you put this query hint on to your query, it tells SQL Server that when it executes the statement to not change the order of the joins in the query. It will join the tables in the exact order that is specified in the query.
Normally the SQL Server optimizer will rearrange your joins to be in the order that it thinks will be optimal for your query to execute.
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);
您将获得:
自您加入以来:
@a
和 @b
和
@b
和 @c
在同一个 b.val
列上,如果将这两个 table 连接在一起(在 a.val
= c.val
上),它是等效的(并且性能更好)然后在最终结果集中引入 @b
中的所有内容。
您在 @a
和 @c
之间的连接条件不是显式的,而是隐式的。
其他杂项信息:
此外,由于您正在加入 table 变量,因此执行计划中每个迭代器的行估计很可能(@a
的 table 扫描, @b
和 @c
) 将是 1。
因此,有了这些信息,SQL 服务器很可能会认为没有理由以任何特定顺序加入 1 row
table。因此,在某些执行中,您可以获得 @a
和 @b
加入执行计划的底部分支,而在其他执行中,您可以获得 @a
和 @c
.
但这只是猜测,可以肯定的是连接条件是隐式的,而不是显式的,这就是为什么你得到 @a
和 @c
先加入。
我最近发现旧代码使用 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.
任何人都可以解释这种情况下的隐式评估吗?
我会说这是查询优化器的事情。首先您的查询:
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;
第二,如果你使用提示:
When you put this query hint on to your query, it tells SQL Server that when it executes the statement to not change the order of the joins in the query. It will join the tables in the exact order that is specified in the query.
Normally the SQL Server optimizer will rearrange your joins to be in the order that it thinks will be optimal for your query to execute.
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);
您将获得:
自您加入以来:
@a
和@b
和@b
和@c
在同一个 b.val
列上,如果将这两个 table 连接在一起(在 a.val
= c.val
上),它是等效的(并且性能更好)然后在最终结果集中引入 @b
中的所有内容。
您在 @a
和 @c
之间的连接条件不是显式的,而是隐式的。
其他杂项信息:
此外,由于您正在加入 table 变量,因此执行计划中每个迭代器的行估计很可能(@a
的 table 扫描, @b
和 @c
) 将是 1。
因此,有了这些信息,SQL 服务器很可能会认为没有理由以任何特定顺序加入 1 row
table。因此,在某些执行中,您可以获得 @a
和 @b
加入执行计划的底部分支,而在其他执行中,您可以获得 @a
和 @c
.
但这只是猜测,可以肯定的是连接条件是隐式的,而不是显式的,这就是为什么你得到 @a
和 @c
先加入。