Inner join vs Where
在性能上(在Oracle中)在
1 2 | SELECT * FROM Table1 T1 INNER JOIN Table2 T2 ON T1.ID = T2.ID |
和
1 2 | SELECT * FROM Table1 T1, Table2 T2 WHERE T1.ID = T2.ID |
号
?
不!相同的执行计划,请看这两个表:
1 2 3 4 5 6 7 8 9 | CREATE TABLE table1 ( id INT, name VARCHAR(20) ); CREATE TABLE table2 ( id INT, name VARCHAR(20) ); |
使用内部联接的查询的执行计划:
1 2 3 4 5 6 7 8 9 10 11 12 13 | -- with inner join EXPLAIN PLAN FOR SELECT * FROM table1 t1 INNER JOIN table2 t2 ON t1.id = t2.id; SELECT * FROM TABLE (DBMS_XPLAN.DISPLAY); -- 0 select statement -- 1 hash join (access("T1"."ID"="T2"."ID")) -- 2 table access full table1 -- 3 table access full table2 |
号
以及使用WHERE子句进行查询的执行计划。
1 2 3 4 5 6 7 8 9 10 11 12 13 | -- with where clause EXPLAIN PLAN FOR SELECT * FROM table1 t1, table2 t2 WHERE t1.id = t2.id; SELECT * FROM TABLE (DBMS_XPLAN.DISPLAY); -- 0 select statement -- 1 hash join (access("T1"."ID"="T2"."ID")) -- 2 table access full table1 -- 3 table access full table2 |
如果查询优化器做得很好,那么这些查询之间应该没有区别。它们只是指定相同期望结果的两种方法。
它们应该完全相同。但是,作为一种编码实践,我宁愿看到连接。它清楚地表达了你的意图,
使用
速度没有区别(我刚刚测试过),执行计划也是一样的。
我不了解Oracle,但我知道旧语法在SQL Server中已被弃用,并将最终消失。在新查询中使用旧语法之前,我将检查Oracle计划如何处理它。
我更喜欢较新的语法,而不是将连接条件与其他需要的where条件混合在一起。在较新的语法中,更清楚地知道是什么创建了联接,以及应用了什么其他条件。在像这样的短查询中,并不是一个大问题,但是当您有一个更复杂的查询时,它会变得更加混乱。由于人们学习基本查询,我倾向于让人们在复杂查询中需要连接语法之前先学会使用它。
另外,我也不清楚Oracle的具体情况,但我知道,即使在SQL Server 2000中,旧式左联接的SQL Server版本也存在缺陷,并且会产生不一致的结果(有时是左联接,有时是交叉联接),因此不应使用它。希望Oracle不会遇到同样的问题,但肯定的是,使用旧语法正确表达左联接和右联接可能会比较困难。
另外,根据我的经验(当然,这是一个严格的个人观点,您可能有不同的经验),使用ANSII标准连接的开发人员倾向于更好地理解连接是什么,以及从数据库中获取数据意味着什么。我相信这是因为大多数具有良好数据库理解能力的人倾向于编写更复杂的查询,在我看来,使用ANSII标准维护这些查询要比使用旧样式容易得多。
它们在逻辑上是相同的,但是在采用ANSI语法的早期版本的Oracle中,在更复杂的情况下,通常会有一些bug,因此在使用它时,有时会遇到Oracle开发人员的抵制。
[奖励积分…]
使用join语法可以更容易地注释掉join,因为它都包含在一行中。如果您正在调试复杂的查询,这将非常有用
正如其他人所说,它们在功能上是相同的,但是连接更清楚地表明了意图。因此,在某些情况下,它可以帮助查询优化程序在当前Oracle版本中(我不知道它是否有帮助),也可以帮助查询优化程序在未来的Oracle版本中(没有人知道),或者如果您更改数据库供应商,它可能会有帮助。
性能应该是相同的,但是我建议使用连接版本,因为当涉及到外部连接时,它提高了清晰度。
也可以使用连接版本避免无意的笛卡尔产品。
第三种效果是使用更简单的where条件更容易读取SQL。
不要忘记,在Oracle中,如果两个表中的联接键属性的名称相同,您也可以将其写为:
1 2 | SELECT * FROM Table1 INNER JOIN Table2 USING (ID); |
。
当然,这也有相同的查询计划。
在表处于第三种正常形式的情况下,表之间的联接不应更改。即加入客户,付款应始终保持不变。
然而,我们必须区分连接和过滤器。连接是关于关系的,过滤器是关于整体的划分。
SQL-92语法鼓励我们将这两个概念分开,它比将连接和过滤器放在WHERE子句上的旧语法更受欢迎,因为WHERE子句比较麻烦。
在PostgreSQL中,绝对没有区别——它们都等同于相同的查询计划。我99%相信这也是甲骨文的情况。
在功能上,它们与前面所说的相同。不过,我同意这样做更好地描述您想要做的事情。很多时候,我一直认为我知道如何查询一些东西,直到我开始做连接,并意识到我想做一个不同于我头脑中的原始查询的查询。
它们都是执行相同操作的内部联接,其中一个只使用较新的ANSI语法。
在功能上,两个查询的处理方式应该相同。但是,经验表明,如果从使用新联接语法的视图中进行选择,那么使用新联接语法来构造查询也是很重要的。如果视图使用"join"语句,Oracle的优化器可能会感到困惑,但是访问视图的查询使用传统的"where"子句中的join方法。
正如基维克所说,执行计划是一样的。
join语句只是更容易阅读,这样就更容易不忘记on条件并得到笛卡尔积。在使用多个类型的联接的长查询中,这些错误很难检测到:select*from T1,t2,其中t1.id=t2.some_字段。
如果您只忘记了一个连接条件,您将得到一个很长的时间来执行查询,返回的记录太多…真的太多了。有些人使用distinct来修补查询,但执行时间仍然很长。
这就是为什么使用join语句肯定是最佳实践:更好的可维护性和更好的可读性。
此外,如果我还记得的话,join在内存使用方面是优化的。
虽然两个查询的标识看起来很明显,但有时会发生一些奇怪的事情。在Oracle10g中,将join谓词从join移动到where时,查询wich有不同的执行计划,但是我不能在简化的表和数据中重现这个问题。我认为这取决于我的数据和统计数字。优化器是一个非常复杂的模块,有时它的行为很神奇。
这就是为什么我们一般不能回答这个问题,因为它取决于数据库内部。但我们应该知道答案必须是"没有区别"。
我今天在检查我们的SP在生产中的一个超时时遇到了这个难题,将一个构建在XML提要上的表的内部联接改为"where"子句……平均执行时间现在是80毫秒,超过1000次执行,而在平均执行时间之前是2.2秒……执行计划的主要区别在于不支持键查找……在使用这两种方法进行测试之前,您不会知道消息。
干杯。
它们都是连接,在哪里做同样的事情。
在mysql查询中,为什么使用join而不是where?