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

时间:2009-04-24 12:09:19

标签: sql mysql sql-server oracle

在JOIN的ON子句中为哪些方式订购条件是否重要?

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

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

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

9 个答案:

答案 0 :(得分:32)

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

  1. 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
    
  2. 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
    
  3. 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)
    
  4. PostgreSQL的家伙,对不起。您的TODO list说:

      

    优化提示(不需要)

         

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

  5. 至于比较中的顺序,在任何RDBMS,AFAIK中无关紧要。

    虽然我个人总是试图估算要搜索的列,并将此列放在左侧(因为它看起来像lvalue)。

    有关详细信息,请参阅this answer

答案 1 :(得分:9)

不,不。

我做的(为了便于阅读)是你的第二个例子。

答案 2 :(得分:5)

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

答案 3 :(得分:1)

不,没有。在一天结束时,您只是在评估是否a = b。

并且作为平等状态的对称属性:

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

因此,无论您检查(12)*=12还是12=(12)*,都会在逻辑上没有区别。

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

答案 4 :(得分:1)

Read this

SqlServer包含一个比这更复杂的情况的优化。

如果您有多个标准,那么通常会对延迟评估(但我需要对边缘情况进行一些研究,如果有的话。)

为了便于阅读,我通常更喜欢

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

我认为以变量的相同顺序引用变量更有意义,但它确实是个人品味的东西。

答案 5 :(得分:1)

我不会使用你的第二个例子的唯一原因:

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'记录。

更正:它不会改变结果。

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

答案 6 :(得分:1)

正如许多人所说:顺序对结果或表现没有影响。

我想指出的是, 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 :名称'名称'不在' equals'左侧的范围内。考虑交换等于'
  • 的任何一方的表达式。
  • CS1938 :名称'名称'不等于'等于'#39;的右侧。考虑交换等于'
  • 的任何一方的表达式。

虽然与标准SQL编码无关,但在适应其中任何一个时,可能需要考虑这一点。

答案 7 :(得分:0)

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

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位于右侧。

答案 8 :(得分:0)

错误: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%'