JOIN 的 ON 子句中引用的表的顺序是不是重要?

Posted

技术标签:

【中文标题】JOIN 的 ON 子句中引用的表的顺序是不是重要?【英文标题】:Does the order of tables referenced in the ON clause of the JOIN matter?JOIN 的 ON 子句中引用的表的顺序是否重要? 【发布时间】:2010-10-21 14:21:21 【问题描述】:

我在 ON 子句中为 JOIN 排序条件的方式是否重要?

select a.Name, b.Status from a
inner join b
on a.StatusID = b.ID

select a.Name, b.Status from a
inner join b
on b.ID = a.StatusID

对性能有影响吗?如果我有多个条件怎么办?

一个订单比另一个更易于维护吗?

【问题讨论】:

【参考方案1】:

JOIN 可以通过在FROM 子句中将表按正确顺序来强制执行:

    mysql 有一个名为 STRAIGHT_JOIN 的特殊子句,它使顺序很重要。

    这将使用b.id 上的索引:

    SELECT  a.Name, b.Status
    FROM    a
    STRAIGHT_JOIN
            b
    ON      b.ID = a.StatusID
    

    这将使用a.StatusID 上的索引:

    SELECT  a.Name, b.Status
    FROM    b
    STRAIGHT_JOIN
            a
    ON      b.ID = a.StatusID
    

    Oracle 有一个特殊提示 ORDERED 来强制执行 JOIN 顺序:

    这将使用b.id 上的索引或在b 上构建哈希表:

    SELECT  /*+ ORDERED */
            *
    FROM    a
    JOIN    b
    ON      b.ID = a.StatusID
    

    这将使用a.StatusID 上的索引或在a 上构建哈希表:

    SELECT  /*+ ORDERED */
            *
    FROM    b
    JOIN    a
    ON      b.ID = a.StatusID
    

    SQL Server 有一个名为 FORCE ORDER 的提示来执行相同的操作:

    这将使用b.id 上的索引或在b 上构建哈希表:

    SELECT  *
    FROM    a
    JOIN    b
    ON      b.ID = a.StatusID
    OPTION (FORCE ORDER)
    

    这将使用a.StatusID 上的索引或在a 上构建哈希表:

    SELECT  *
    FROM    b
    JOIN    a
    ON      b.ID = a.StatusID
    OPTION (FORCE ORDER)
    

    PostgreSQL 伙计们,对不起。你的TODO list 说:

    优化器提示(不需要)

    优化器提示用于解决优化器中的问题。我们宁愿报告和修复问题。

至于比较中的顺序,在任何RDBMS,AFAIK中都没有关系。

虽然我个人总是尝试估计将搜索哪一列并将该列放在左侧(使其看起来像 lvalue)。

更多详情请参阅this answer

【讨论】:

关于“PostgreSQL 伙计们,对不起”-官方 TODO wiki.postgresql.org/wiki/Todo#Features_We_Do_Not_Want 中的“优化器提示”。 我有点惊讶。 OP 询问了 ON 子句的顺序,还展示了一个示例,其中他没有反转表,而只反转了 ON-子句,但这个答案只处理表顺序反转的情况。还是最后一条评论“至于对比中的顺序……”指的是它吗? @TimSchmelter:至于比较中的顺序,在任何 RDBMS 中都没有关系,AFAIK。【参考方案2】:

不,它没有。

我所做的(为了可读性)是你的第二个例子。

【讨论】:

【参考方案3】:

没有。数据库应该根据整个标准确定最佳执行计划,而不是通过按顺序查看每个项目来创建它。您可以通过请求两个查询的执行计划来确认这一点,您会看到它们是相同的(您会发现即使是截然不同的查询,只要它们最终指定相同的逻辑,通常都会编译成相同的执行计划)。

【讨论】:

【参考方案4】:

不,没有。归根结底,您实际上只是在评估是否 a=b。

正如平等的对称性所说:

对于任意数量 a 和 b,如果 a = b,则 b = a。

所以无论您检查(12)*=12 还是12=(12)* 在逻辑上都没有区别。

如果值相等,则加入,如果不相等,则不加入。无论您是在第一个示例还是第二个示例中指定它,都没有区别。

【讨论】:

这是已发布问题的正确答案。【参考方案5】:

正如许多人所说:订单对结果或性能没有影响。

我想指出的是,LINQ to SQL 只允许第一种情况

例如,下面的例子效果很好,...

var result = from a in db.a
             join b in db.b on a.StatusID equals b.ID
             select new  Name = a.Name, Status = b.Status 

...虽然这会在 Visual Studio 中引发错误:

var result = from a in db.a
             join b in db.b on b.ID equals a.StatusID
             select new  Name = a.Name, Status = b.Status 

会引发这些编译器错误:

CS1937:名称“name”不在“equals”左侧的范围内。考虑交换 'equals' 两边的表达式。 CS1938:名称“name”不在“equals”右侧的范围内。考虑交换 'equals' 两边的表达式。

虽然与标准 SQL 编码无关,但在习惯使用其中任何一种时,这可能是需要考虑的一点。

【讨论】:

【参考方案6】:

Read this

SqlServer 包含针对远比这复杂的情况的优化。

如果你有多个标准,通常会懒惰地评估东西(但如果有的话,我需要围绕边缘情况做一些研究。)

为了可读性,我通常更喜欢

SELECT Name, Status FROM a 
JOIN b 
ON a.StatusID = b.ID

我认为按照声明变量的顺序引用变量更有意义,但这确实是个人品味。

【讨论】:

【参考方案7】:

我不使用您的第二个示例的唯一原因:

select a.Name, b.Status 
from a
inner join b
  on b.ID = a.StatusID

您的用户更有可能回来说“即使他们没有状态记录,我也可以查看所有 a.name 吗?”而不是“即使 b.status 没有名称记录,我也可以看到所有的信息吗?”,所以为了提前计划这个例子,我会使用 On a.StatusID = b.ID 来期待 LEFT Outer Join。这假设您可以有没有“b”的表“a”记录。

更正:它不会改变结果。

这可能是一个有争议的问题,因为用户永远不想改变他们的要求。

【讨论】:

在 LEFT 或 RIGHT 连接中的顺序无关紧要,所以我可以看到在这种情况下并没有真正的区别。即使 ON 子句是“b.ID = a.StatusID”,您仍然可以将子句更改为 LEFT OUTER JOIN @Tom - 很高兴你指出了这一点。我差点惊恐发作。【参考方案8】:

不,没关系。但这里有一个示例可以帮助您提高查询的可读性(至少对我而言)

select a.*, b.*
from tableA a
     inner join tableB b
          on a.name=b.name
               and a.type=b.type

每个表引用都在单独的行上,每个连接条件都在单独的行上。制表符有助于保持属于什么的直。

我喜欢做的另一件事是让我在 on 语句中的条件与表格的顺序相同。所以如果先a后b,a在左边,b在右边。

【讨论】:

【参考方案9】:

错误:ON 子句在其右侧引用表(php sqlite 3.2)

替换这个

LEFT JOIN itm08 i8 ON  i8.id= **cdd01.idcmdds** and i8.itm like '%ormit%'  

LEFT JOIN **comodidades cdd01** ON cdd01.id_registro = u.id_registro 

为此

LEFT JOIN **comodidades cdd01** ON cdd01.id_registro = u.id_registro

LEFT JOIN itm08 i8 ON  i8.id= **cdd01.idcmdds** and i8.itm like '%ormit%'

【讨论】:

以上是关于JOIN 的 ON 子句中引用的表的顺序是不是重要?的主要内容,如果未能解决你的问题,请参考以下文章

TSQL——on 子句的顺序是不是重要

什么是sql中的连接顺序[重复]

View 的 ON 子句与 JOIN 不按顺序出现

hive 的 left semi join

关于在left join的on子句中限制左边表的取值时出现非期望的结果

LINQ Join 与 On 子句中的多个条件