SQL中连接的顺序是否重要?

271

不考虑性能,查询 A 和 B 的结果会相同吗?C 和 D 呢?

----- Scenario 1: 
-- A (left join)
select *
from   a left join b
           on <blahblah>
       left join c
           on <blahblan>


-- B (left join)
select *
from   a left join c
           on <blahblah>
       left join b
           on <blahblan>  

----- Scenario 2:   
-- C (inner join)
select *
from   a join b
           on <blahblah>
       join c
           on <blahblan>


-- D (inner join)
select *
from   a join c
           on <blahblah>
       join b
           on <blahblan>  

12
“<blahblah>” 是什么?你是将 A 和 B 连接还是将 A 和 B、B 和 C 连接? - beny23
7
嗨Beny,我问题中的代码是一个抽象。我不关心将A连接到B或A连接到C,我只想知道像那样的语法是否会提供相同的结果。 - Just a learner
4个回答

316
对于INNER连接,不,顺序不重要。只要将选择从"SELECT *"更改为"SELECT a.*,b.*,c.*",查询将返回相同的结果。
对于(LEFT、RIGHT或FULL) OUTER连接,是的,顺序很重要,而且事情变得更加复杂了。
首先,外连接不满足交换律,因此"a LEFT JOIN b"与"b LEFT JOIN a"不同。
外连接也不满足结合律,所以在涉及交换律和结合律两种属性的示例中:
a LEFT JOIN b 
    ON b.ab_id = a.ab_id
  LEFT JOIN c
    ON c.ac_id = a.ac_id
Equivalent to的意思是:等同于。
a LEFT JOIN c 
    ON c.ac_id = a.ac_id
  LEFT JOIN b
    ON b.ab_id = a.ab_id

但是:

a LEFT JOIN b 
    ON  b.ab_id = a.ab_id
  LEFT JOIN c
    ON  c.ac_id = a.ac_id
    AND c.bc_id = b.bc_id

不等于:

a LEFT JOIN c 
    ON  c.ac_id = a.ac_id
  LEFT JOIN b
    ON  b.ab_id = a.ab_id
    AND b.bc_id = c.bc_id

这里是另一个(希望更简单的)关联性示例。将其视为 (a LEFT JOIN b) LEFT JOIN c


a LEFT JOIN b 
    ON b.ab_id = a.ab_id          -- AB condition
 LEFT JOIN c
    ON c.bc_id = b.bc_id          -- BC condition

这相当于a LEFT JOIN (b LEFT JOIN c)

a LEFT JOIN  
    b LEFT JOIN c
        ON c.bc_id = b.bc_id          -- BC condition
    ON b.ab_id = a.ab_id          -- AB condition

仅因为我们有“好”的ON条件。ON b.ab_id = a.ab_idc.bc_id = b.bc_id都是相等性检查,不涉及NULL比较。

甚至可以使用其他运算符或更复杂的条件,例如:ON a.x <= b.xON a.x = 7ON a.x LIKE b.xON (a.x,a.y) = (b.x,b.y),这两个查询仍然等价。

但是,如果任何一个条件涉及到IS NULL或与null相关的函数,例如COALESCE(),比如条件是b.ab_id IS NULL,那么这两个查询就不等价了。


4
只要其中一个表的所有列都是 NULL,没有谓词可以满足,那么说外连接是可结合的更为准确,而不是说只要谓词不涉及 IS NULL 或与空值相关的函数就可结合。可以很容易地想象出一种能够满足前一描述但不能满足后一描述的谓词,例如 a.somecol > 0 OR b.someothercol > 0;在这种情况下,可结合性可能会失败。 - Mark Amery
1
但是,我认为从技术上讲,只要谓词不满足我在这里描述的任何一个条件,就可以说OUTER JOIN是可结合的:https://dev59.com/_WIj5IYBdhLWcg3wq2tz#20022925(第一个条件也会破坏INNER JOIN的结合性,但这是一种如此廉价和明显的方法来破坏它,也许不值得一提)。另外值得指出的是,最常见的JOIN类型——基于外键的JOIN——不满足这两个条件,因此很好地保持了结合性。 - Mark Amery
2
@MarkAmery 谢谢,我在那个问题上一直很难构思句子(我已经给你的回答点赞了 ;)) - ypercubeᵀᴹ
1
实际上,所有的连接类型 都是 结合的,根据 SQL 标准和结合的数学定义,但它们看起来不是结合的,因为重新排列括号需要将 ON 子句(即“连接规范”)移动到一个新位置。不过这只是语法问题。如果使用关系代数符号(其中连接规范放置在连接运算符下方),则关联性变得更加明显。你的论点只显示了外连接不是 可交换的,这是正确的。 - Lukas Eder
@ypercubeᵀᴹ ON 的顺序重要吗?例如,如果我连接两个表Table A和Table B,使用A.id = B.id,那么如果我按照B.id = A.id的顺序进行ON操作,结果是否相同?谢谢。 - Roxy'Pro
显示剩余7条评论

11
如果您在连接B之前尝试使用B字段加入C,即:
SELECT A.x, 
       A.y, 
       A.z 
FROM A 
   INNER JOIN C
       on B.x = C.x
   INNER JOIN B
       on A.x = B.x

如果顺序不对,你的查询将会失败。

在这种情况下,顺序很重要。

是的,这是正确的,应该修改答案。 - Nir Pengas

6

对于常规的Joins,它并不重要。TableA join TableB会产生与TableB join TableA相同的执行计划(因此您的C和D示例将是相同的)。

但是对于左连接和右连接而言,它很重要。TableA left Join TableBTableB left Join TableA不同,但它与TableB right Join TableA相同。


6
这只涉及可交换性,但问题中的例子表明提问者对结合律也感兴趣。ypercube的回答解决了两个问题。 - Mark Amery

3

Oracle优化器在内部连接时选择表的连接顺序。 优化器只在简单的FROM子句中选择表的连接顺序。 您可以在Oracle网站上查看相关文档。 对于左、右外连接,最受欢迎的答案是右边。 优化器不仅选择最佳的连接顺序,还为每个表选择最佳的索引。连接顺序会影响最佳索引的选择。如果某个表是内部表,则优化器可能会选择一个索引作为该表的访问路径,但如果该表是外部表(且没有进一步的限制条件),则不会选择索引。

优化器只在简单的FROM子句中选择表的连接顺序。大多数使用JOIN关键字的连接都被展开成简单的连接,因此优化器会选择它们的连接顺序。

优化器不会为外连接选择连接顺序;它使用语句中指定的顺序。

在选择连接顺序时,优化器会考虑以下因素: 每个表的大小 每个表可用的索引 在特定连接顺序下,表上的索引是否有用 每个连接顺序需要扫描的行数和页数


1
我认为这是一个好答案。可以重新措辞以解释Oracle优化器之所以这样做,是因为在某些情况下确实存在等价性。还有另一个人写了类似的东西:https://mastel.org/blog/when-join-order-matters,它解释说排序被视为优化器的提示,但优化器也可以重新排序连接以提高性能。 - Pierre-Luc Bertrand

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接