首页 文章

INNER JOIN ON vs WHERE子句

提问于
浏览
793

为简单起见,假设所有相关字段均为 NOT NULL .

你可以做:

SELECT
    table1.this, table2.that, table2.somethingelse
FROM
    table1, table2
WHERE
    table1.foreignkey = table2.primarykey
    AND (some other conditions)

要不然:

SELECT
    table1.this, table2.that, table2.somethingelse
FROM
    table1 INNER JOIN table2
    ON table1.foreignkey = table2.primarykey
WHERE
    (some other conditions)

这两个在 MySQL 中以相同的方式工作吗?

10 回答

  • 22

    一旦您需要开始向查询添加更多表,隐式连接(这是您的第一个查询被称为)变得更加混乱,难以阅读和难以维护 . 想象一下,在四个或五个不同的表上进行相同的查询和连接类型......这是一场噩梦 .

    使用显式连接(第二个示例)更易读,易于维护 .

  • 10

    我知道你在谈论MySQL,但无论如何:在Oracle 9中,显式连接和隐式连接会产生不同的执行计划 . 在Oracle 10中已经解决的AFAIK:不再存在这样的差异了 .

  • 1

    隐式连接ANSI语法较旧,不太明显,不推荐使用 .

    此外,关系代数允许 WHERE 子句和 INNER JOIN 中的谓词的可互换性,因此即使具有 WHERE 子句的 INNER JOIN 查询也可以使优化器重新排列谓词 .

    我建议您以尽可能最简单的方式编写查询 .

    有时这包括使 INNER JOIN 相对"incomplete"并将一些标准放在 WHERE 中,只是为了使过滤标准列表更容易维护 .

    例如,而不是:

    SELECT *
    FROM Customers c
    INNER JOIN CustomerAccounts ca
        ON ca.CustomerID = c.CustomerID
        AND c.State = 'NY'
    INNER JOIN Accounts a
        ON ca.AccountID = a.AccountID
        AND a.Status = 1
    

    写:

    SELECT *
    FROM Customers c
    INNER JOIN CustomerAccounts ca
        ON ca.CustomerID = c.CustomerID
    INNER JOIN Accounts a
        ON ca.AccountID = a.AccountID
    WHERE c.State = 'NY'
        AND a.Status = 1
    

    但这当然取决于它 .

  • 57

    它们具有不同的人类可读意义 .

    但是,根据查询优化器,它们可能与计算机具有相同的含义 .

    您应始终编码以便可读 .

    也就是说,如果这是内置关系,请使用显式连接 . 如果要匹配弱相关数据,请使用where子句 .

  • 117

    其他人指出,INNER JOIN有助于人类的可读性,这是首要任务;我同意 . 让我试着解释为什么连接语法更具可读性 .

    一个基本的SELECT查询是这样的:

    SELECT stuff
    FROM tables
    WHERE conditions
    

    SELECT子句告诉我们 what 我们要回来了; FROM子句告诉我们 where 我们从中得到它,而WHERE子句告诉我们 which 我们得到的 .

    JOIN是关于表的声明,它们如何绑定在一起(概念上,实际上,绑定到单个表中) . 任何控制表的查询元素 - 我们在哪里JOIN元素去哪里 . 将join-elements放入WHERE子句会使 whichwhere-from 混为一谈 . 这就是首选JOIN语法的原因 .

  • 27

    我还要指出,使用较旧的语法更容易出错 . 如果在没有ON子句的情况下使用内部联接,则会出现语法错误 . 如果您使用旧语法并忘记where子句中的一个连接条件,您将获得交叉连接 . 开发人员经常通过添加distinct关键字(而不是修复连接,因为他们仍然没有意识到连接本身被破坏)来解决这个问题,这似乎可以解决问题,但会大大减慢查询速度 .

    另外,如果您使用旧语法进行交叉连接进行维护,维护者如何知道您是否有一个(有需要交叉连接的情况)或者是否应该修复的事故?

    让我指出这个问题,看看为什么如果你使用左连接,隐式语法是坏的 . Sybase *= to Ansi Standard with 2 different outer tables for same inner table

    加上(个人咆哮),使用显式连接的标准已超过20年,这意味着隐式连接语法已经过时了20年 . 您是否会使用已经过时20年的语法编写应用程序代码?你为什么要编写数据库代码?

  • 12

    SQL:2003标准更改了一些优先级规则,因此JOIN语句优先于“逗号”连接 . 这实际上可以根据设置的方式更改查询结果 . 当MySQL 5.0.12切换到符合标准时,这会给某些人带来一些问题 .

    因此,在您的示例中,您的查询将起作用 . 但是如果你添加了第三个表:SELECT ... FROM table1,table2 JOIN table3 ON ... WHERE ...

    在MySQL 5.0.12之前,首先连接table1和table2,然后连接table3 . 现在(5.0.12及以上),首先连接table2和table3,然后连接table1 . 它并不总是改变结果,但它可以,你甚至可能没有意识到它 .

    我再也不会使用“逗号”语法了,选择了第二个例子 . 无论如何,它的可读性要高得多,JOIN条件与JOIN相关,而不是单独的查询部分 .

  • 4

    INNER JOIN 是您应该使用的ANSI语法 .

    它通常被认为更具可读性,尤其是当您加入大量表时 .

    只要有需要,它也可以很容易地用_76934替换 .

    WHERE 语法更加面向关系模型 .

    两个表 JOIN ed的结果是应用过滤器的表的笛卡尔积,其仅选择具有匹配的连接列的那些行 .

    使用 WHERE 语法更容易看到这一点 .

    如例如,在MySQL(以及一般的SQL)中,这两个查询是同义词 .

    另请注意,MySQL也有一个 STRAIGHT_JOIN 子句 .

    使用此子句,您可以控制 JOIN 顺序:在外部循环中扫描哪个表以及在内部循环中扫描哪个表 .

    您无法使用 WHERE 语法在MySQL中控制此操作 .

  • 630

    ANSI连接语法肯定更具可移植性 .

    我正在进行Microsoft SQL Server的升级,我还要提到的是,对于2005 sql server及更高版本,不支持SQL Server中外连接的= =语法(没有兼容模式) .

  • 154

    Applying conditional statements in ON / WHERE

    在这里,我已经解释了逻辑查询处理步骤 .


    参考:内部Microsoft®SQLServer™2005 T-SQL查询
    出版商:微软出版社
    发布日期:2006年3月7日
    打印ISBN-10:0-7356-2313-9
    打印ISBN-13:978-0-7356-2313-2
    页数:640

    Inside Microsoft® SQL Server™ 2005 T-SQL Querying

    (8)  SELECT (9) DISTINCT (11) TOP <top_specification> <select_list>
    (1)  FROM <left_table>
    (3)       <join_type> JOIN <right_table>
    (2)       ON <join_condition>
    (4)  WHERE <where_condition>
    (5)  GROUP BY <group_by_list>
    (6)  WITH {CUBE | ROLLUP}
    (7)  HAVING <having_condition>
    (10) ORDER BY <order_by_list>
    

    与其他编程语言不同的SQL的第一个显着方面是代码处理的顺序 . 在大多数编程语言中,代码按其编写顺序进行处理 . 在SQL中,处理的第一个子句是FROM子句,而首先出现的SELECT子句几乎是最后处理的 .

    每个步骤都会生成一个虚拟表,用作以下步骤的输入 . 这些虚拟表对调用者(客户端应用程序或外部查询)不可用 . 只有最后一步生成的表才会返回给调用者 . 如果查询中未指定某个子句,则只需跳过相应的步骤 .

    逻辑查询处理阶段的简要说明

    如果步骤的描述现在似乎没有多大意义,请不要太担心 . 这些是作为参考提供的 . 在场景示例之后的部分将更详细地介绍这些步骤 .

    • FROM:在FROM子句的前两个表之间执行笛卡尔积(交叉连接),结果生成虚拟表VT1 .

    • ON:ON过滤器应用于VT1 . 只有 <join_condition> 为TRUE的行才会插入VT2 .

    • OUTER(join):如果指定了OUTER JOIN(而不是CROSS JOIN或INNER JOIN),则保留的一个或多个未找到匹配项的表中的行将作为外行添加到VT2的行中,生成VT3 . 如果FROM子句中出现两个以上的表,则在最后一个连接的结果和FROM子句中的下一个表之间重复应用步骤1到步骤3,直到处理完所有表 .

    • WHERE:WHERE过滤器应用于VT3 . 只有 <where_condition> 为TRUE的行才会插入VT4 .

    • GROUP BY:VT4中的行根据GROUP BY子句中指定的列列表按组排列 . 生成VT5 .

    • CUBE | ROLLUP:超级组(组的组)被添加到VT5的行中,生成VT6 .

    • HAVING:HAVING过滤器应用于VT6 . 只有 <having_condition> 为TRUE的组才会插入VT7 .

    • SELECT:处理SELECT列表,生成VT8 .

    • DISTINCT:从VT8中删除重复的行 . 生成VT9 .

    • ORDER BY:VT9中的行根据ORDER BY子句中指定的列列表进行排序 . 生成游标(VC10) .

    • TOP:从VC10的开头选择指定的行数或百分比 . 生成表VT11并将其返回给调用者 .


    因此,(INNER JOIN)ON将在应用WHERE子句之前过滤数据(此处VT的数据计数将减少) . 随后的连接条件将使用过滤后的数据执行,从而提高性能 . 之后,只有WHERE条件才会应用过滤条件 .

    (在ON / WHERE中应用条件语句在少数情况下不会产生太大差异 . 这取决于您加入的表数和每个连接表中可用的行数)

相关问题