SQL - 这些连接的区别是什么?

6
我应该现在就知道这个问题的答案,但是下面两个语句有什么区别(如果有的话)?
嵌套连接:
SELECT
    t1.*
FROM
    table1 t1
    INNER JOIN table2 t2
        LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
    ON t2.table2_ID = t1.table1_ID

更传统的连接方式:

SELECT
    t1.*
FROM
    table1 t1
    INNER JOIN table2 t2 ON t2.table2_ID = t1.table1_ID
    LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID

当您执行它们时,它们是否会产生相同的结果? - Luc M
第二个比第一个容易理解多了——即使你在第一个中加上(括号)也是如此。期待在这个问题上投出一个好的答案。 - Philip Kelley
在我的有限测试中,是的,它们确实给出了相同的结果。但是,我不想基于此做任何假设,因为我只是进行了快速和有限的数据测试。 - TehOne
2
天啊,我又回忆起了重写使用“可视化”查询设计器构建的视图的恐怖经历。一个查询中左右连接、嵌套连接以及尝试弄清楚没有括号的and/or操作顺序的恐惧。 - dotjoe
4个回答

5

嗯,这是操作顺序问题。

SELECT
    t1.*
FROM
    table1 t1
    INNER JOIN table2 t2
        LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
    ON t2.table2_ID = t1.table1_ID

可以改写为:

SELECT
    t1.*
FROM
       table1 t1                                                       -- inner join t1
    INNER JOIN 
       (table2 t2 LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID)  -- with this 
    ON t2.table2_ID = t1.table1_ID                                     -- on this condition

基本上,首先你需要根据连接条件table3_ID = table2_ID使用左联接从t2和t3中进行连接,然后使用INNER JOIN将t1与t2进行连接,连接条件为table2_ID = table1_ID。

在第二个例子中,首先使用INNER JOIN将t1与t2进行连接,然后在条件table2_ID = table1_ID的基础上,使用LEFT JOIN将结果内部连接与表格t3进行连接。

SELECT
    t1.*
FROM
    table1 t1
    INNER JOIN table2 t2 ON t2.table2_ID = t1.table1_ID
    LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID        

可以重写为:

SELECT
    t1.*
FROM
        (table1 t1 INNER JOIN table2 t2 ON t2.table2_ID = t1.table1_ID) -- first inner join
    LEFT JOIN                                                           -- then left join
        table3 t3 ON t3.table3_ID = t2.table2_ID                        -- the result with this

编辑

我很抱歉。我的第一条评论是错误的。这两个查询将产生相同的结果,但在某些情况下(当表1仅包含表2中的子集时),第一个查询可能比第二个查询执行得慢,因为LEFT JOIN将首先被执行,然后才与表1相交。而第二个查询允许查询优化器发挥作用。


1
明显的,操作顺序是不同的,但实际上有任何区别(性能、结果、任何方面)吗? - Roee Adler
1
请举一个数据的例子,使查询会返回不同的结果。我无法生成任何结果。 - Shannon Severance
好的,谢谢大家对此的看法。那么它基本上就像我想的那样。结果将是相同的,但是查询可能执行不同。为了使用的方便性,我会更改旧的(嵌套)查询以使用更传统的语法。 - TehOne

4

针对您提供的具体示例,我认为生成的查询计划不应该有任何区别,但可读性确实存在差异。第二个示例要容易得多。

如果您在示例中反转连接类型,则可能会得到非常不同的结果。

SELECT    t1.*
FROM    table1 t1
    LEFT JOIN table2 t2 ON t2.table2_ID = t1.table1_ID
    INNER JOIN table3 t3 ON t3.table3_ID = t2.table2_ID

-- may not produce the same results as...

SELECT    t1.*
FROM    table1 t1
    LEFT JOIN table2 t2
        INNER JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
    ON t2.table2_ID = t1.table1_ID

基于连接顺序在许多情况下确实很重要的事实 - 应该仔细考虑如何编写您的连接语法。如果您发现第二个示例是您真正想要实现的内容,我建议您重新编写查询,以便更加强调连接顺序...

SELECT    t1.*
FROM    table2 t2
        INNER JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
        RIGHT JOIN table1 t1 ON t2.table2_ID = t1.table1_ID

2

要了解这两个查询之间的区别,最好的方法是比较两个查询的查询计划。

如果对于table2中的某一行总是有table3中的行,则IF的结果集没有区别。

我在我的数据库上尝试了一下,查询计划的区别在于: 1. 对于第一个查询,优化器选择先在table2和table3上进行连接。 2. 对于第二个查询,优化器选择先连接table1和table2。


对我来说,我的实际查询的执行计划完全相同。 - TehOne

0

只要您的数据库管理系统优化器达到标准,您应该在这两个查询之间看不到任何区别。然而,即使对于大型高成本平台,我也不会自信地做出这种假设,因此如果发现查询计划(以及执行时间)有所不同,我也不会感到惊讶。


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