Oracle联接 - 传统语法VS ANSI语法之间的比较

时间:2013-09-19 09:34:53

标签: sql oracle oracle11g oracle10g oracle12c

序言

最近,我看到有太多的极客评论Oracle的问题,说“不要使用(+)运算符,而是使用JOIN语法”。

问题

我确实看到两者都运作良好。但是使用它们之间的真正区别是什么让你觉得使用它们?我希望得到答案,更多来自经验。

 1. Is there anything to do with limitations in application, performance, 
    etc. while using them?

 2. What would you suggest for me?

我确实在Oracle documentation上阅读了一些内容,但还不足以让我理解或对综合信息感到满意。

注意:我打算迁移200多个软件包和程序,如果使用关键字而不是(+)

  3. Also is there any freeware tools to do the rewrite?

发布样本

┌───────────────────────────────────┬─────────────────────────────────────────────┐
│ INNER JOIN - CONVENTIONAL         │ INNER JOIN - ANSI SYNTAX                    │
├───────────────────────────────────┼─────────────────────────────────────────────┤
│ SELECT                            │ SELECT                                      │
│      emp.deptno                   │       ename,                                │
│ FROM                              │       dname,                                │
│      emp,                         │       emp.deptno,                           │
│      dept                         │       dept.deptno                           │
│ WHERE                             │ FROM                                        │
│      emp.deptno = dept.deptno;    │       scott.emp INNER JOIN scott.dept       │
│                                   │       ON emp.deptno = dept.deptno;          │
├───────────────────────────────────┼─────────────────────────────────────────────┤
│ LEFT OUTER JOIN - CONVENTIONAL    │ LEFT OUTER JOIN - ANSI SYNTAX               │
├───────────────────────────────────┼─────────────────────────────────────────────┤
│ SELECT                            │ SELECT                                      │
│      emp.deptno                   │      ename,                                 │
│ FROM                              │      dname,                                 │
│      emp,                         │      emp.deptno,                            │
│      dept                         │      dept.deptno                            │
│ WHERE                             │ FROM                                        │
│      emp.deptno = dept.deptno(+); │      scott.emp LEFT OUTER JOIN scott.dept   │
│                                   │      ON emp.deptno = dept.deptno;           │
├───────────────────────────────────┼─────────────────────────────────────────────┤
│ RIGHT OUTER JOIN - CONVENTIONAL   │ RIGHT OUTER JOIN - ANSI SYNTAX              │
├───────────────────────────────────┼─────────────────────────────────────────────┤
│ SELECT                            │ SELECT                                      │
│      emp.deptno                   │      ename,                                 │
│ FROM                              │      dname,                                 │
│      emp,                         │      emp.deptno,                            │
│      dept                         │      dept.deptno                            │
│ WHERE                             │ FROM                                        │
│      emp.deptno(+) = dept.deptno; │      scott.emp RIGHT OUTER JOIN scott.dept  │
│                                   │      ON emp.deptno = dept.deptno;           │
├───────────────────────────────────┼─────────────────────────────────────────────┤
│ FULL OUTER JOIN - CONVENTIONAL    │ FULL OUTER JOIN - ANSI SYNTAX               │
├───────────────────────────────────┼─────────────────────────────────────────────┤
│ SELECT                            │ SELECT                                      │
│      *                            │      *                                      │
│ FROM                              │ FROM                                        │
│      emp,                         │      scott.emp FULL OUTER JOIN scott.dept   │
│      dept                         │      ON emp.deptno = dept.deptno;           │
│ WHERE                             │                                             │
│      emp.deptno = dept.deptno(+)  │                                             │
│ UNION ALL                         │                                             │
│ SELECT                            │                                             │
│      *                            │                                             │
│ FROM                              │                                             │
│      emp,                         │                                             │
│      dept                         │                                             │
│ WHERE                             │                                             │
│      emp.deptno(+) = dept.deptno  │                                             │
│      AND emp.deptno IS NULL;      │                                             │
└───────────────────────────────────┴─────────────────────────────────────────────┘

PS :阅读所有分组更新的答案摘要。

11 个答案:

答案 0 :(得分:24)

如果您的200多个软件包使用“老式”语法按预期工作,那就试试吧。 迁移到ANSI语法后,SQL不会开始表现更好 - 它只是不同的语法。

如上所述,ANSI语法更清晰 - 如果在某些多列外连接中忘记(+),则不会进行正常连接。
在过去,有一些ANSI语法的错误,但如果你使用最新的11.2或12.1应该已经修复。
当然,您更了解您的环境和优先级 - 正如SchmitzIT所说 - ANSI语法是SQL标准的一部分,它将有助于使用其他一些RDBMS产品。

答案 1 :(得分:14)

在11g中你应该使用ANSI连接语法。它更灵活(支持完全外连接和分区连接),并且如文档所述:

  

Oracle强烈建议您使用前一个示例中显示的更灵活的FROM子句连接语法。

这就足够了。

答案 2 :(得分:9)

将答案分组

  1. 使用显式JOIN而不是隐式(无论它们是否为外连接)是因为使用隐式连接意外创建笛卡尔积更容易。使用显式JOIN,您不能“偶然”创建一个。涉及的表越多,您错过一个连接条件的风险就越高。
  2. 与ANSI连接相比,基本上(+)受到严重限制。此外,它仅在Oracle中可用,而所有主要DBMS都支持ANSI连接语法
  3. 迁移到ANSI语法后SQL不会开始表现更好 - 它只是不同的语法。
  4. Oracle强烈建议您使用前一个示例中显示的更灵活的FROM子句连接语法。在过去,有一些ANSI语法的错误,但如果你使用最新的11.2或12.1应该已经修复。
  5. 使用JOIN运算符可确保您的SQL代码符合ANSI标准,从而可以更轻松地将前端应用程序移植到其他数据库平台。
  6. 连接条件对每个表具有非常低的选择性,并且对理论叉积中的元组具有高选择性。 where语句中的条件通常具有更高的选择性。
  7. Oracle在内部将ANSI语法转换为(+)语法,您可以在执行计划的谓词信息部分中看到这种情况。
  8. 在12c引擎上使用ANSI语法的可能陷阱

    在12c中加入JOIN中的bug的可能性。见here

    关注:

    Quest SQL optimizer tool将SQL重写为ANSI语法。

答案 3 :(得分:5)

除了其他人提到的原因之外,使用JOIN运算符可确保您的SQL代码符合ANSI标准,从而可以更轻松地将前端应用程序移植到其他数据库平台。

答案 4 :(得分:4)

根据选择性分离谓词

将查询分隔为连接条件以及条件可以为优化程序提供额外提示的位置。连接条件对每个表具有非常低的选择性,并且对理论叉积中的元组具有高选择性。 where语句中的条件通常具有更高的选择性。

在左边每行的连接条件中,右边很可能有一个值(反之亦然)。所以这样的条件很好地连接来自两个表的结果,但它们对从结果集中消除每个表中的值没有多大帮助。

where子句中的条件通常可用于从结果集中删除一个表中的各个行。

提示(人类!)优化器

这是一个很好的策略,首先运行各个表的where条件,并从结果集中消除尽可能多的行。之后,可以使用连接条件来组合幸存的行。

目前尚不清楚Oracle优化器是否真正使用SQL语句中条件的位置作为优化查询的提示。我想它更感兴趣的是表统计中的硬性事实(Oracle在11g R1中处理不同连接的方式有一些变化,有关详细信息,请参阅Oracle优化工具团队的this post)。

至少对我来说,当我尝试理解和优化查询时,了解一个语句是否在单个表上具有选择性是非常有帮助的。当你想在ON子句中放入多个条件(例如ON (a.x=b.x AND a.y=b.y)而不是将其中一个条件放在where clasue中时,你也应该考虑这个:只需检查条件的选择性。

结论

对于现有查询,请保持语法不变。在创建新查询或重构现有查询时,请尝试使用“JOIN ON”语法对谓词的谓词进行排序:如果在单个表上不能选择它,请将其放在ON部分中,否则放在WHERE部分中。 / p>

答案 5 :(得分:4)

作为一种惯例,您应该始终使用ANSI语法。最好不要对包装和程序进行返工。相反,当您单独对这些脚本进行任何维护时,您可以修复问题。由于语法原因,计划不会有任何差异。

Quest SQL优化器重写所有可能的组合以找到更好的计划。所以你仍然需要从100多个结果中搜索一个SQL。

答案 6 :(得分:3)

外部联接中使用的(+)符号是外部联接的Oracle语法

根据从可靠的oracle源收集的信息,我可以看到你可以为现有的包保留Oracle外连接语法(+),因为有200多个包,因为内部Oracle仍然将它们从ANSI语法转换为Oracle语法。

请稍后在使用(+)运算符

的限制时使用ANSI语法

请查找链接以获取有关(+)签名的详细说明外部联接可能有助于您确定迁移

Oracle Outer Join syntax and ANSI syntax

Limitations of using (+) Outer joins

More information about Oracle outer join

(+) Outer join Operator recommended in Java when using Oracle JDBC drivers

答案 7 :(得分:2)

我在不同的项目中使用了这两种方法,我更喜欢JOIN语法。

  • ON子句和过滤器中的连接条件有明确的分离 WHERE条款中的条件。
  • 更容易阅读和维护大 查询有很多连接。

答案 8 :(得分:2)

根据工作经验,使用JOIN而不是(+)更简单,更快速,更好看并更好地使用解决方案,特别是当您使用多数据库选择时(在整个同义词中) ,在大数据库中有很多表格(例如:40多个表格)(1000多个表格,一些表格超过20亿行),你会感觉到很大的不同。

答案 9 :(得分:2)

有些评论者说(+)语法不允许完全外连接。确实如此,所以这不是问题所在:( LEFT OUTER JOIN)UNION ALL(RIGHT OUTER JOIN)。

其他人说性能是进行转换的原因。这是一堆BS,特别是在SQL中。当然,有一些指导方针,但是每个查询和每个数据库都有自己的特点,你必须根据具体情况进行调整。

除了不是标准之外,从(+)切换的原因是它的局限性,而不是新的显式语法:http://docs.oracle.com/cd/E16655_01/server.121/e17209/queries006.htm#SQLRF52354。从这里开始阅读:“Oracle建议您使用FROM子句OUTER JOIN语法而不是Oracle连接运算符。”

答案 10 :(得分:0)

直到上周,我一直是ANSI加入的拥护者。直到我的选择之一,蒂尔才意识到自己的行为很怪异。挖掘Oracle错误库之后,我了解到Oracle不本地支持ANSI联接-ANSI联接被转换为(+)表示法,然后进行处理。而且此翻译有一些无法接受的错误。这是不可接受的,因为我们的客户端没有应用补丁程序,并且因为甚至在12c版本中也引入了一些新的错误-非常简单的测试用例,其中包含三个表,一个记录和两个外部联接。好像男人根本没有做自动回归测试