内部连接vs Where

(在oracle中)在性能上有区别吗

Select * from Table1 T1
Inner Join Table2 T2 On T1.ID = T2.ID

Select * from Table1 T1, Table2 T2
Where T1.ID = T2.ID

?

136852 次浏览

如果查询优化器的工作是正确的,那么这些查询之间应该没有区别。它们只是指定相同期望结果的两种方法。

在PostgreSQL中,它们绝对没有区别——它们都等同于相同的查询计划。我99%确信甲骨文也是如此。

它们应该完全一样。然而,作为一种编码实践,我宁愿看到Join。它清楚地表达了你的意图,

它们都是做同样事情的内部连接,一个只是使用更新的ANSI语法。

从功能上讲,它们是相同的。不过,我同意使用连接更好地描述您想要做的事情。很多时候,我认为我知道我想如何查询一些东西,直到我开始做连接,并意识到我想做一个不同于我头脑中的原始查询。

它们在逻辑上是相同的,但是在采用ANSI语法的Oracle早期版本中,在更复杂的情况下经常会出现错误,所以在使用它时有时会遇到来自Oracle开发人员的阻力。

我不了解Oracle,但我知道旧的语法在SQL Server中被弃用了,最终会消失。在我在新的查询中使用旧语法之前,我会检查Oracle计划用它做什么。

我更喜欢更新的语法,而不是将连接标准与其他所需的where条件混合在一起。在新的语法中,创建连接的内容和应用的其他条件更加清晰。在这样的短查询中并不是一个大问题,但是当您有一个更复杂的查询时,它会变得更加混乱。由于人们学习基本的查询,我倾向于让人们在复杂查询中使用连接语法之前先学习使用它。

再次,我不知道Oracle,但我知道SQL Server版本的旧风格左连接是有缺陷的,甚至在SQL Server 2000,并给出不一致的结果(有时左连接有时交叉连接),所以它不应该被使用。希望Oracle不会遇到同样的问题,但可以肯定的是,左右连接在旧语法中很难正确表达。

另外,根据我的经验(当然,这完全是个人观点,你可能有不同的经验),使用ansi标准连接的开发人员倾向于更好地理解连接是什么以及它在从数据库中获取数据方面的意义。我相信这是因为大多数对数据库有良好理解的人倾向于编写更复杂的查询,而在我看来,使用ANSII标准比旧风格更容易维护。

使用JOIN使代码更容易阅读,因为它是自解释的。

速度(我刚刚测试过)没有区别,执行计划是相同的。

的确,在功能上,这两个查询应该以相同的方式处理。但是,经验表明,如果您正在从使用新连接语法的视图中进行选择,那么使用该语法组织查询也很重要。如果视图使用了“join”语句,Oracle的优化器可能会感到困惑,但是访问视图的查询使用了传统的“where”子句连接方法。

性能应该是相同的,但我建议使用连接版本,因为在涉及到外部连接时提高了清晰度。

另外,使用连接版也可以避免无意的笛卡尔积。

第三个效果是使用更简单的where条件更容易读取SQL。

不!同样的执行计划,请看下面两个表:

CREATE TABLE table1 (
id INT,
name VARCHAR(20)
);


CREATE TABLE table2 (
id INT,
name VARCHAR(20)
);

使用内部连接的查询的执行计划:

-- 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子句的查询的执行计划。

-- 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中,如果连接键属性在两个表中命名相同,你也可以这样写:

select *
from Table1 inner join Table2 using (ID);

当然,这也有相同的查询计划。

[为了加分…]

使用JOIN语法允许您更容易地注释掉连接,因为它全部包含在一行中。如果你正在调试一个复杂的查询,这个可以是有用的

正如其他人所说,它们在功能上是相同的,但是JOIN更清楚地表达了意图。因此,它五月帮助查询优化器在当前的oracle版本在某些情况下(我不知道它是否这样做),它五月帮助查询优化器在未来的oracle版本(没有人知道),或者它五月帮助如果你改变数据库供应商。

尽管两个查询的身份似乎很明显,但有时会发生一些奇怪的事情。在Oracle 10g中将连接谓词从join移动到WHERE时,我遇到了具有不同执行计划的查询(对于WHERE计划更好),但我无法在简化的表和数据中重现此问题。我认为这取决于我的数据和统计。优化器是一个相当复杂的模块,有时它表现得很神奇。

这就是为什么我们不能一般地回答这个问题,因为它取决于DB内部。但我们应该知道答案必须是'没有任何区别'。

今天,当我在生产环境中检查我们的一个sp的超时时,我遇到了这个难题,将一个从XML提要构建的表上的内部连接更改为“where”子句....现在执行1000次的平均执行时间是80ms,而以前的平均执行时间是2.2秒……执行计划的主要区别是取消了键查找…除非你用这两种方法测试过,否则你不会知道答案。

欢呼。

在表采用第三范式的场景中,表之间的连接不应该改变。即加入客户和付款应始终保持不变。

但是,我们应该区分连接过滤器。联接是关于关系的,而过滤器是关于划分整体的。

一些作者,参考标准(即吉姆梅尔顿;艾伦·r·西蒙(1993)。理解新的SQL:完整指南。摩根考夫曼。11 - 12页。ISBN 978-1-55860-245-8.)写了在FROM子句中采用JOIN语法而不是逗号分隔表的好处。

我完全同意这个观点。

有几种方法可以编写SQL并达到相同的结果,但对于许多进行团队工作的人来说,源代码的可读性是一个重要方面,当然,从澄清源代码的意义上讲,将表之间的关系从特定的过滤器中分离出来是一个巨大的飞跃。

它们都是连接,做同样的事情。

看看在MySQL查询中,为什么使用join而不是where?

就像kiewik说的,执行计划是一样的。

JOIN语句只是更容易阅读,使它更容易不忘记ON条件和得到笛卡尔积。在使用多个连接类型的长查询中,这些错误很难检测到:SELECT * FROM t1, t2 WHERE t1.id=t2.some_field。

如果你只忘记了一个连接条件,你会得到一个很长的执行查询,返回太多的记录…真的太多了。有些人使用DISTINCT来修补查询,但执行起来仍然很长。

这就是为什么使用JOIN语句肯定是最佳实践:具有更好的可维护性和更好的可读性。

此外,如果我没记错的话,JOIN在内存使用方面进行了优化。

我有一个附加好的答案:

这就是分别定义为SQL92和SQL89的内容,它们之间没有性能差异,尽管可以省略INNER这个词(只使用JOIN就足够清楚了,在最简单的查询中保存了5个键盘笔画,现在想象一下在大的查询中有多少笔画)。