【问题标题】:Inner join vs Where内连接 vs Where
【发布时间】:2010-09-12 09:45:26
【问题描述】:

两者之间的性能(在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

?

【问题讨论】:

  • 仅作记录,我已经看到查询返回不同的结果仅通过将连接更改为 where 子句
  • @BlackTigerX:不同的结果?是否涉及任何外部联接?因为我看不出inner join ... on 与在where 子句中放置等效连接标准之间会发生什么不同的结果。
  • 旧版oracle数据库中不存在join
  • @MajidTaheri:你说的 Oracle 版本是多少年? Oracle 支持的任何版本都支持 JOIN 表示法。
  • 寻找基于琐碎案例的一般答案或最佳实践。希望看到包含多个 AND 条件的更复杂 where 子句的“重新匹配”。至少 SQL Server 有一个交叉点。

标签: sql performance oracle


【解决方案1】:

不!同一个执行计划,看这两张表:

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

【讨论】:

  • 我真的很想看看甲骨文是否有任何官方文档说明这一点
【解决方案2】:

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

【讨论】:

  • 是的,性能应该是一样的。但是 SELECT * FROM Table1, Table2 WHERE ... 语法是 EVIL!
  • 我发现 FOR INNER JOINS 比 SQL-92 语法更容易理解。您的里程可能会有所不同。
  • 我发现 WHERE 语法比 INNER JION 更容易阅读 - 我猜它就像 Vegemite。世界上大多数人可能觉得它很恶心,但长大后吃它的孩子们喜欢它。
  • Vegemite 确实很讨厌,但我又一次喜欢 scppple。去图吧。
  • @Darryl 我认为JOINs 更容易阅读,因为加入表格的条件是立即在那里定义的,而不是WHERE 子句中的“某处”。我更喜欢保留WHERE 子句来限制数据集(例如WHERE DATE > (SYSDATE - 1)),而不是定义表如何相互关联(例如WHERE T1.ID = T2.ID)。对于像问题示例这样的小表几乎没有什么区别,但对于涉及多个表和多个条件的大型查询,我认为它使查询更容易理解。
【解决方案3】:

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

【讨论】:

  • 我同意。特别是如果您要加入多个表,如果您正在执行显式联接,则解析 select 语句会容易得多。
  • 确实如此。连接表示两组数据之间的语义关系,但 where 表示过滤集。 +1
【解决方案4】:

使用JOIN 使代码更易于阅读,因为它是不言自明的。

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

【讨论】:

  • 谢谢。我正在寻找这两种方法之间的速度压缩。
【解决方案5】:

[获得奖励积分...]

使用 JOIN 语法可以让您更轻松地将连接注释掉,因为它全部包含在一行中。如果您正在调试复杂的查询,这可能很有用

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

【讨论】:

  • 或者... 轻松地将 INNER JOINS 更改为 LEFT JOINS,这样您就可以看到哪个连接导致您错过了预期的行。我这样做是因为我一次完成整个查询。如果你注释掉 INNER JOINS,你就必须做一个消除过程。它需要更长的时间。但是为您 +1,因为除了可读性之外,这是我最喜欢 INNER JOINS 的原因之一!
【解决方案6】:

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

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

再说一次,我并不特别了解 Oracle,但我知道旧式左连接的 SQL Server 版本即使在 SQL Server 2000 中也存在缺陷并且给出不一致的结果(有时左连接有时是交叉连接),所以它永远不应该使用。希望 Oracle 不会遇到同样的问题,但是用旧语法正确表达左连接和右连接肯定会更加困难。

另外,根据我的经验(当然,这完全是个人意见,您可能有不同的经验),使用 ANSII 标准联接的开发人员往往对联接是什么以及它在从数据库中获取数据的术语。我相信这是因为大多数对数据库有很好理解的人倾向于编写更复杂的查询,而且在我看来,使用 ANSII 标准比旧样式更容易维护这些查询。

【讨论】:

  • 阿门兄弟。打倒JOINERS!!
【解决方案7】:

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

【讨论】:

  • 早期版本的 Oracle 有这方面的错误?多早?什么版本?
  • Metalink 有详细信息……它们会到处弹出。
【解决方案8】:

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

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

第三个效果是使用更简单的 WHERE 条件更易于阅读 SQL。

【讨论】:

  • 我真的认为关键是标准不明确时的无意影响。如果您指定连接类型,您将确切地知道您得到了什么。我发现不同的数据库甚至同一数据库平台的不同版本在隐式连接中处理空值的方式不同。当您指定左/右内/外时,您会花时间考虑哪个是正确的。当您使用模棱两可的方法时,您假设它按照您希望/打算的方式工作。
【解决方案9】:

不要忘记,在 Oracle 中,如果两个表中的连接键属性名称相同,您也可以这样写:

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

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

【讨论】:

  • 我回滚了版本,因为上一个版本改变了答案的意思
【解决方案10】:

在表为第 3 范式的情况下,表之间的连接不应更改。 IE。加入 CUSTOMERS 和 PAYMENTS 应始终保持不变。

但是,我们应该区分 joinsfilters。连接是关于关系的,过滤器是关于分割一个整体的。

一些作者,参考标准(即 Jim Melton;Alan R. Simon (1993)。理解新 SQL:完整指南。Morgan Kaufmann。第 11-12 页。ISBN 978-1-55860-245- 8.),写了关于在 FROM 子句中采用 JOIN 语法而不是逗号分隔表的好处。

我完全同意这个观点。

有几种方法可以编写 SQL 并获得相同的结果,但对于许多进行团队合作的人来说,源代码的易读性是一个重要方面,当然,从特定的过滤器中区分表之间的相互关系是一个很大的飞跃澄清源代码。

【讨论】:

  • Inner join on 表示在哪里交叉连接。逗号是优先级低于关键字连接的交叉连接。 On vs "filter" 与内部连接无关。 NF 与查询无关。标准中的任何内容都没有促进关键字连接而不是逗号。微不足道的优化处理和类似的地方。这个答案是一堆误解。
  • 1) 我猜@philipxy 试图说“在 FROM 子句中,用逗号分隔的表与 CROSS JOINed 表具有相同的含义。”我同意这一点。当然,您可以坚持使用旧语法,并且可以与 JOIN 子句共存。 RDBMS 优化器将完全理解这两种情况是相同的(当然,如果它们是等价的)并将制定相同的计划。
【解决方案11】:

在 PostgreSQL 中,绝对没有区别 - 它们都等同于相同的查询计划。我 99% 确定 Oracle 也是如此。

【讨论】:

    【解决方案12】:

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

    【讨论】:

      【解决方案13】:

      从功能上讲,它们与前面所说的相同。我同意虽然加入更适合准确描述您想要做什么。很多时候我都以为我知道我想查询什么,直到我开始进行连接并意识到我想做一个与我脑海中原来的查询不同的查询。

      【讨论】:

        【解决方案14】:

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

        【讨论】:

        • 这更多是视图的问题,而不是连接的问题。
        【解决方案15】:

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

        这就是为什么我们一般不能回答这个问题,因为它取决于数据库内部。但我们应该知道答案必须是“没有差异”。

        【讨论】:

          【解决方案16】:

          我今天在检查我们的一个 sp 在生产中的超时时遇到了这个难题,将由 xml 提要构建的表上的内部连接更改为“where”子句......现在平均执行时间为 80 毫秒,超过 1000执行,而之前的平均执行时间是 2.2 秒...执行计划的主要区别是密钥查找的消失...在您使用这两种方法进行测试之前您不会知道的消息。

          干杯。

          【讨论】:

          • 请注意,多年后 - 您观察到的更可能是重建存储过程的产物,而不是更改语法。
          【解决方案17】:

          它们都是连接,并且在哪里做同样的事情。

          看看In MySQL queries, why use join instead of where?

          【讨论】:

            【解决方案18】:

            正如kiewik所说,执行计划是一样的。

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

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

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

            此外,如果我记得很清楚,JOIN 在内存使用方面进行了优化。

            【讨论】:

              【解决方案19】:

              我有一个补充 good answer:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-06-24
                • 2017-07-31
                • 1970-01-01
                • 1970-01-01
                • 2014-04-29
                相关资源
                最近更新 更多