为简单起见,假设所有相关字段都为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中工作方式相同吗?


当前回答

如果您经常编写动态存储过程,那么您会爱上第二个示例(使用where)。如果你有各种各样的输入参数和大量的变形混乱,那么这是唯一的方法。否则,它们将运行相同的查询计划,因此在经典查询中肯定没有明显的区别。

其他回答

INNER JOIN是你应该使用的ANSI语法。

它通常被认为更具可读性,特别是当您连接许多表时。

当需要时,还可以轻松地用OUTER JOIN替换它。

WHERE语法更面向关系模型。

两个表连接的结果是应用筛选器的表的笛卡尔积,筛选器只选择连接列匹配的行。

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

至于你的例子,在MySQL中(通常在SQL中),这两个查询是同义词。

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

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

在MySQL中不能使用WHERE语法来控制这一点。

一旦需要向查询中添加更多的表,隐式连接(第一个查询就是隐式连接)将变得更加混乱、难以阅读和维护。想象一下,在四五个不同的表上执行相同的查询和类型的连接……这是一场噩梦。

使用显式连接(第二个示例)可读性更强,也更容易维护。

我还将指出,使用旧语法更容易出错。如果使用不带ON子句的内部连接,则会出现语法错误。如果您使用旧的语法并且忘记了where子句中的一个连接条件,那么您将得到一个交叉连接。开发人员通常通过添加不同的关键字来解决这个问题(而不是修复连接,因为他们仍然没有意识到连接本身已经损坏),这可能看起来解决了问题,但会大大降低查询速度。

此外,对于维护,如果您在旧语法中有一个交叉连接,维护者如何知道您是否有意要有一个交叉连接(在需要交叉连接的情况下),或者这是一个应该修复的意外?

让我向您指出这个问题,看看为什么使用左连接时隐式语法不好。 Sybase *= Ansi标准与2个不同的外部表相同的内部表

另外,使用显式连接的标准已经超过20年了,这意味着隐式连接语法在这20年里已经过时了。你会使用已经过时20年的语法来编写应用程序代码吗?为什么要编写数据库代码呢?

我知道你说的是MySQL,但不管怎样: 在Oracle 9中,显式连接和隐式连接将生成不同的执行计划。AFAIK在Oracle 10+中已经解决了:不再有这样的区别了。

在ON / WHERE中应用条件语句

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


参考:Microsoft®SQL Server™2005 T-SQL查询 出版社:微软出版社 时间:2006年3月7日 打印ISBN-10: 0-7356-2313-9 打印ISBN-13: 978-0-7356-2313-2 页:640

Microsoft®SQL Server™2005 T-SQL查询内部

(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: A Cartesian product (cross join) is performed between the first two tables in the FROM clause, and as a result, virtual table VT1 is generated. ON: The ON filter is applied to VT1. Only rows for which the <join_condition> is TRUE are inserted to VT2. OUTER (join): If an OUTER JOIN is specified (as opposed to a CROSS JOIN or an INNER JOIN), rows from the preserved table or tables for which a match was not found are added to the rows from VT2 as outer rows, generating VT3. If more than two tables appear in the FROM clause, steps 1 through 3 are applied repeatedly between the result of the last join and the next table in the FROM clause until all tables are processed. WHERE: The WHERE filter is applied to VT3. Only rows for which the <where_condition> is TRUE are inserted to VT4. GROUP BY: The rows from VT4 are arranged in groups based on the column list specified in the GROUP BY clause. VT5 is generated. CUBE | ROLLUP: Supergroups (groups of groups) are added to the rows from VT5, generating VT6. HAVING: The HAVING filter is applied to VT6. Only groups for which the <having_condition> is TRUE are inserted to VT7. SELECT: The SELECT list is processed, generating VT8. DISTINCT: Duplicate rows are removed from VT8. VT9 is generated. ORDER BY: The rows from VT9 are sorted according to the column list specified in the ORDER BY clause. A cursor is generated (VC10). TOP: The specified number or percentage of rows is selected from the beginning of VC10. Table VT11 is generated and returned to the caller.



Therefore, (INNER JOIN) ON will filter the data (the data count of VT will be reduced here itself) before applying the WHERE clause. The subsequent join conditions will be executed with filtered data which improves performance. After that, only the WHERE condition will apply filter conditions.

(在ON / WHERE中应用条件语句在少数情况下不会有太大区别。这取决于你连接了多少个表,以及每个连接表中可用的行数)