【问题标题】:Does the join order matter in SQL?连接顺序在 SQL 中重要吗?
【发布时间】:2012-03-25 18:35:10
【问题描述】:

不管性能,我会从下面的查询 A 和 B 中得到相同的结果吗? C和D呢?

-- A
select *
from   a left join b
           on <blahblah>
       left join c
           on <blahblan>


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

-- C
select *
from   a join b
           on <blahblah>
       join c
           on <blahblan>


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

【问题讨论】:

  • &lt;blahblah&gt; 是什么?你是加入 A 到 B 和 A 到 C,还是加入 A 到 B 和 B 到 C?
  • 嗨 Beny,我的问题中的代码是一个抽象。我不关心将 A 加入 B 或 A 加入 C,我只是想知道这样的语法是否会提供相同的结果。

标签: sql join relational-database


【解决方案1】:

对于INNER 连接,不,顺序无关紧要。只要您将选择从 SELECT * 更改为 SELECT a.*, b.*, c.*,查询将返回相同的结果。


对于(LEFTRIGHTFULLOUTER 加入,是的,顺序很重要 - 并且(更新)事情要多得多复杂。

首先,外连接不可交换,所以a LEFT JOIN bb LEFT JOIN a不一样

外连接也不具有关联性,因此在您的示例中同时涉及(交换性和关联性)属性:

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

等价于

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 &lt;= b.xON a.x = 7ON a.x LIKE b.xON (a.x, a.y) = (b.x, b.y),这两个查询仍然是等效的。

但是,如果其中任何一个涉及IS NULL 或与COALESCE() 等空值相关的函数,例如如果条件为b.ab_id IS NULL,那么这两个查询将不等价。

【讨论】:

  • 如果一个表中的所有列都为 NULL 的行不能满足任何谓词,则说外连接是关联的更正确,而不是说它是关联的,只要谓词不涉及 IS NULL 或“与空值相关的函数”。可以很容易地想象一个满足前一个描述但不满足后者的谓词,比如a.somecol &gt; 0 OR b.someothercol &gt; 0;在这种情况下,关联性可能会失败。
  • 但是,我认为只要谓词不满足我在这里描述的任何一个条件,就可以说 OUTER JOIN 是关联的:stackoverflow.com/questions/20022196/…(其中第一个也是破坏了 INNER JOIN 的关联性,但它是一种廉价而明显的破坏方法,也许不值得一提。)还值得指出的是,最常见的 JOIN 类型 - 外键连接 - 不满足任何一个这些条件,因此很好且具有关联性。
  • @MarkAmery 谢谢,在那一点上我很难组织我的句子(我已经赞成你的答案;)
  • ypercube 我有一个INNER JOIN 和一个追随者LEFT JOIN。它是否像这样工作,首先查询将Filter 基于INNER JOIN 的记录,然后将LEFT JOIN 应用于Filtered 记录?
  • 事实上,所有连接类型都是关联的,如 SQL 标准和关联性的数学定义所指定的,但它们不会出现 关联,因为重新排列括号需要将ON 子句(即“连接规范”)移动到新位置。不过,这只是语法。如果您使用关系代数表示法(连接规范位于连接运算符下方),则关联性会变得更加明显。您的论点仅表明外连接不是可交换,这是正确的
【解决方案2】:

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

对于左右连接,它确实如此。 TableA left Join TableBTableB left Join TableA 不同,但与 TableB right Join TableA 相同

【讨论】:

  • 这仅涉及交换性,但问题中的示例表明提问者对关联性感兴趣。 ypercube 的回答解决了这两个问题。
【解决方案3】:

如果您在加入 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

您的查询将失败,因此在这种情况下顺序很重要。

【讨论】:

  • 是的,这是正确的,正确的答案应该修改。
【解决方案4】:

Oracle 优化器 为内部连接选择表的连接顺序。 优化器仅在简单的 FROM 子句中选择表的连接顺序。 你可以在他们的网站上查看 oracle 文档。 而对于左、右外连接,投票最多的答案是正确的。 优化器为每个表选择最佳连接顺序以及最佳索引。连接顺序会影响哪个索引是最佳选择。如果是内部表,优化器可以选择索引作为表的访问路径,但如果是外部表则不能(并且没有进一步的限定)。

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

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

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

【讨论】:

  • 我相信这是一个很好的答案。它可以被改写来解释 Oracle 优化器这样做是因为它在某些情况下确实是等价的。还有另一个人写了类似的东西:mastel.org/blog/when-join-order-matters,它解释了排序被作为优化器的提示,但优化器也可以重新排序连接以提高性能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-25
  • 2010-09-07
  • 2010-12-30
  • 1970-01-01
  • 2017-07-31
相关资源
最近更新 更多