Oracle的加号(+)表示法和ansi JOIN符号之间的区别?

时间:2009-07-28 12:03:45

标签: sql performance oracle join

使用oracle加上符号(+)而不是ansi标准join表示法有什么区别?

性能有差异吗?

加号表示法是否已弃用?

8 个答案:

答案 0 :(得分:96)

AFAIK,(+)表示法仅用于向后兼容,因为Oracle在加入ANSI标准之前就推出了它。它是特定于Oracle的,当有相同的符合标准的版本时,你应该避免在新代码中使用它。

编辑: 两者之间似乎存在差异,(+)符号具有ANSI连接语法所没有的限制。 Oracle自己建议您不要使用(+)表示法。 Oracle® Database SQL Language Reference 11g Release 1 (11.1)中的完整说明:

Oracle建议您使用FROM子句OUTER JOIN语法而不是Oracle join运算符。使用Oracle连接运算符(+)的外连接查询受以下规则和限制的约束,这些规则和限制不适用于FROM子句OUTER JOIN语法:

  • 您不能在同时包含(+)子句连接语法的查询块中指定FROM运算符。
  • (+)运算符只能出现在WHERE子句中,或者在TABLE子句中左对齐(指定FROM子句时)的上下文中出现,并且只能应用于表格或视图的列。
  • 如果A和B通过多个连接条件连接,则必须在所有这些条件下使用(+)运算符。如果不这样做,那么Oracle数据库将仅返回由简单连接产生的行,但没有警告或错误,建议您没有外连接的结果。

  • 如果在外部查询中指定一个表而在内部查询中指定另一个表,则(+)运算符不会生成外部联接。

  • 虽然自联接有效,但您无法使用(+)运算符将表外连接到自身。

例如,以下语句无效:

SELECT employee_id, manager_id
FROM employees
WHERE employees.manager_id(+) = employees.employee_id;

但是,以下自加入有效:

SELECT e1.employee_id, e1.manager_id, e2.employee_id
FROM employees e1, employees e2
WHERE e1.manager_id(+) = e2.employee_id;
  • (+)运算符只能应用于列,而不能应用于任意表达式。但是,任意表达式可以包含一个或多个标有(+)运算符的列。

  • 包含WHERE运算符的(+)条件无法与使用OR逻辑运算符的其他条件合并。

  • WHERE条件无法使用IN比较条件将标有(+)运算符的列与表达式进行比较。

如果WHERE子句包含将表B中的列与常量进行比较的条件,则必须将(+)运算符应用于该列,以便Oracle返回表A中的行,它为此列生成了空值。否则,Oracle仅返回简单连接的结果。

在执行两个以上表对的外连接的查询中,单个表可以是仅为一个其他表的空生成表。因此,您不能将(+)运算符应用于A和B的连接条件中的B列以及B和C的连接条件。有关外连接的语法,请参阅SELECT

答案 1 :(得分:12)

从Oracle 10开始仍然支持该表示法(我相信11)。它的使用被认为是“老式的”,并且不像ANSI JOIN语法那样是数据库可移植的。它也被认为更不易读,虽然如果你来自+背景习惯ANSI JOIN可能需要一点时间。在向Oracle投掷砖块之前要知道的重要事项是,在ANSI委员会完成连接定义之前,他们开发了+语法。

没有性能差异;他们表达同样的事情。

编辑:通过“不那么便携”我应该说“只在Oracle SQL中支持”

答案 2 :(得分:12)

我同意Tony Miller的回答,并想补充一点,你可以用(+)synthax做一些事情:

  • 你不能FULL OUTER JOIN两个表,你必须手动使用UNION ALL两个连接,
  • 您不能将表连接到两个或多个表,您必须手动创建子查询(即:b.id = a.id (+) AND c.id = a.id (+)不是可接受的子句)

答案 3 :(得分:9)

最全面的答案显然是nagul

正在寻找快速翻译/映射到ANSI语法的人的补充:

--
-- INNER JOIN
--
SELECT *
FROM EMP e
INNER JOIN DEPT d ON d.DEPTNO = e.DEPTNO;

 -- Synonym in deprecated oracle (+) syntax
SELECT *
FROM EMP e,
     DEPT d
WHERE d.DEPTNO = e.DEPTNO;

--
-- LEFT OUTER JOIN
--
SELECT *
FROM EMP e
LEFT JOIN DEPT d ON d.DEPTNO = e.DEPTNO;

 -- Synonym in deprecated oracle (+) syntax
SELECT *
FROM EMP e,
     DEPT d
WHERE d.DEPTNO (+) = e.DEPTNO;

--
-- RIGHT OUTER JOIN
--
SELECT *
FROM EMP e
RIGHT JOIN DEPT d ON d.DEPTNO = e.DEPTNO;

-- Synonym in deprecated oracle (+) syntax
SELECT *
FROM EMP e,
     DEPT d
WHERE d.DEPTNO = e.DEPTNO(+);

--
-- CROSS JOIN
--
SELECT *
FROM EMP e
CROSS JOIN DEPT d;

 -- Synonym in deprecated oracle (+) syntax
SELECT *
FROM EMP e,
     DEPT d;

--
-- FULL JOIN
--
SELECT *
FROM EMP e
FULL JOIN DEPT d ON d.DEPTNO = e.DEPTNO;

-- Synonym in deprecated oracle (+) syntax !NOT WORKING!
SELECT *
FROM EMP e,
     DEPT d
WHERE d.DEPTNO (+) = e.DEPTNO(+);

答案 4 :(得分:2)

使用 ANSI 语法优于旧的 Oracle加入语法的一个很好的理由是,没有机会意外创建笛卡儿产品。有了更多的表,有可能错过使用旧的Oracle连接语法的隐式连接,但是,使用ANSI语法,您不能错过任何连接,因为您必须明确提及它们。

Oracle外连接语法 ANSI / ISO语法之间的区别。

LEFT OUTER JOIN -

SELECT e.last_name,
  d.department_name
FROM employees e,
  departments d
WHERE e.department_id = d.department_id(+);

SELECT e.last_name,
  d.department_name
FROM employees e
LEFT OUTER JOIN departments d
ON (e.department_id = d.department_id);

RIGHT OUTER JOIN -

SELECT e.last_name,
  d.department_name
FROM employees e,
  departments d
WHERE e.department_id(+) = d.department_id;

SELECT e.last_name,
  d.department_name
FROM employees e
RIGHT OUTER JOIN departments d
ON (e.department_id = d.department_id);

FULL OUTER JOIN -

在11gR1中对hash full outerjoin进行原生支持之前,Oracle会在内部以下列方式转换FULL OUTER JOIN -

SELECT e.last_name,
  d.department_name
FROM employees e,
  departments d
WHERE e.department_id = d.department_id(+)
UNION ALL
SELECT NULL,
  d.department_name
FROM departments d
WHERE NOT EXISTS
  (SELECT 1 FROM employees e WHERE e.department_id = d.department_id
  );

SELECT e.last_name,
  d.department_name
FROM employees e
FULL OUTER JOIN departments d
ON (e.department_id = d.department_id);

查看this

答案 5 :(得分:1)

Oracle(+)表示法仅用于Oracle,特定于供应商。并且, ANSI标准加入符号可以用于任何RDBMS(如Sql Server,MySql等)。否则,Oracle(+)表示法和ANSI标准加入表示法之间没有区别。

如果您在Sql Query中使用ANSI标准连接表示法,则可以在任何RDBMS中使用相同的查询。并且,如果您移植您的数据库<强>从Oracle到任何其他RDBMS 在这种情况下你必须使用ANSI语法

答案 6 :(得分:1)

我使用(+)表示法,因为几乎所有与Oracle Apps r12相关的查询都基于此。我没有在Oracle APPS查询中看到一个带有标准“join”表达式的SQL查询(甚至是Oracle本身提供的那些)。如果您不相信我,只需谷歌任何Oracle应用相关信息。例如:Fixed assets related queries

答案 7 :(得分:1)

  1. 使用显式JOIN而不是隐式(无论它们是否为外连接)是因为使用隐式连接意外创建笛卡尔积更容易。使用明确的JOIN,你不能意外地#34;创造一个。涉及的表越多,您错过一个连接条件的风险就越高。
  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语法转换为(+)语法,您可以在执行计划的谓词信息部分中看到这种情况。