Разница между Oracle плюс (+) и ANSI JOIN?

65

В чем разница между использованием оракула плюс обозначение (+) над стандартной записью ansi join?

Есть ли разница в производительности?

Является ли обозначение "плюс" устаревшим?

Теги:
performance
join

8 ответов

92
Лучший ответ

AFAIK, нотация (+) присутствует только для обратной совместимости, потому что Oracle дебютировала перед тем, как был установлен стандарт ANSI для объединений. Это специфично для Oracle, и вам следует избегать использования его в новом коде, если имеется эквивалентная версия, совместимая со стандартами.

Изменить: Кажется, что существуют различия между ними, а нотация (+) имеет ограничения, которые не имеют синтаксиса ANSI join. Сам Oracle рекомендует не использовать нотацию (+). Полное описание здесь, в Справочник по языку базы данных Oracle Database 11g Выпуск 1 (11.1):

Oracle рекомендует использовать синтаксис FROM OUTER JOIN, а не оператор объединения Oracle. Запросы внешнего соединения, использующие оператор объединения Oracle (+), подчиняются следующим правилам и ограничениям, которые не применяются к синтаксису FROM OUTER JOIN:

  • Вы не можете указать оператор (+) в блоке запроса, который также содержит синтаксис соединения предложения FROM.
  • Оператор (+) может отображаться только в предложении WHERE или в контексте левой корреляции (при указании предложения TABLE) в предложении FROM и может применяться только к столбцу таблицы или вида.
  • Если A и B соединены несколькими условиями соединения, вы должны использовать оператор (+) во всех этих условиях. Если вы этого не сделаете, тогда Oracle Database вернет только строки, полученные в результате простого соединения, но без предупреждения или ошибки, чтобы сообщить вам, что у вас нет результатов внешнего соединения.

  • Оператор (+) не создает внешнее соединение, если вы укажете одну таблицу во внешнем запросе и другую таблицу во внутреннем запросе.

  • Вы не можете использовать оператор (+) для внешнего соединения таблицы для себя, хотя самосоединения действительны.

Например, следующий оператор недействителен:

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;
  • Оператор (+) может применяться только к столбцу, а не к произвольному выражению. Однако произвольное выражение может содержать один или несколько столбцов, помеченных оператором (+).

  • A WHERE условие, содержащее оператор (+), нельзя комбинировать с другим условием, используя логический оператор OR.

    Условие
  • A WHERE не может использовать условие сравнения IN для сравнения столбца, помеченного оператором (+), с выражением.

Если предложение WHERE содержит условие, которое сравнивает столбец из таблицы B с константой, тогда оператор (+) должен быть применен к столбцу, чтобы Oracle возвращал строки из таблицы A, для которых он сгенерировал null для этой колонки. В противном случае Oracle возвращает только результаты простого соединения.

В запросе, который выполняет внешние соединения более двух пар таблиц, одна таблица может быть таблицей с нулевым значением только для одной другой таблицы. По этой причине вы не можете применить оператор (+) к столбцам B в условии соединения для A и B и условия соединения для B и C. Обратитесь к SELECT для синтаксиса внешнего соединения.

  • 0
    Спасибо. Хорошее объяснение
  • 0
    docs.oracle.com/cd/B19306_01/server.102/b14200/queries006.htm
12

Я согласен с ответом Тони Миллера и хотел бы добавить, что есть также несколько вещей, которые вы НЕ можете делать с (+) синтаксисом:

  • Вы не можете ПОЛНОСТЬЮ ВСТУПИТЬ В ДРУГИЕ таблицы, вам нужно сделать это вручную с помощью UNION ALL из двух объединений,
  • Вы не можете вставлять таблицу в две или более таблицы, вам нужно вручную создать подзапрос (т.е.: b.id = a.id (+) AND c.id = a.id (+) не является приемлемым предложением)
  • 0
    Как насчет цепочки внешних объединений, например, a.b_id = b.id (+) AND b.c_id = c.id (+) Я унаследовал нечто подобное, и я a.b_id = b.id (+) AND b.c_id = c.id (+) вопросом, что действительно возвращается, если происходит соединение a b до нуля
  • 0
    @Dan Вы можете без проблем соединять внешние соединения в "старом стиле" A -> B -> C Применяются те же правила, что и для стандартных объединений ANSI: цепочка внешних объединений разрывается, если одно из ее звеньев является регулярным соединением. Другими словами, A LEFT JOIN B INNER JOIN C эквивалентно A JOIN B JOIN C
12

Обозначения по-прежнему поддерживаются по версии Oracle 10 (и я считаю, что 11). Это использование считается "старомодным", а также не является портативной базой данных, как синтаксис ANSI JOIN. Он также считается гораздо менее читаемым, хотя, если вы исходите из фона +, привыкающего к ANSI JOIN, может занять немного времени. Важная вещь, которую нужно знать перед тем, как бросить кирпич в Oracle, заключается в том, что они разработали свой синтаксис + до того, как комитет ANSI завершил определения для объединений.

Нет разницы в производительности; они выражают одно и то же.

Изменить: "Не переносимым" я должен был сказать "поддерживается только в Oracle SQL"

  • 13
    Имейте в виду, однако, что было несколько ошибок, когда оптимизатор Oracle генерировал неверные планы запросов или неверные результаты при использовании синтаксиса ANSI. В 11.1 это встречается гораздо реже, чем в 10.1 или 10.2, но это случалось достаточно часто и сжигало достаточно людей, которые были ранними приверженцами синтаксиса ANSI, так как большие части сообщества Oracle не решались принять синтаксис ANSI.
  • 6
    У меня есть один пример, когда вы все еще вынуждены использовать старый синтаксис соединения Oracle: если вы создаете MATERIALIZED VIEW с FAST REFRESH вы не можете использовать синтаксис ANSI. Я только что проверил страницу Oracle для этой проблемы, она все еще присутствует. Oracle не считает это ошибкой! Подробности смотрите в Oracle Doc ID 1372720.1, если у вас есть доступ к поддержке Oracle.
Показать ещё 1 комментарий
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(+);
1

Одна из веских причин использовать синтаксис 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);

ПРАВИЛЬНАЯ ВСТРОЕННАЯ РАБОТА -

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);

ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ -

До того, как встроенная поддержка хэш-функции полностью нарушена в 11gR1, 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);

Посмотрите это.

1
  • Используйте явные JOIN, а не имплицитные (независимо от того, являются ли они внешними объединениями или нет) заключается в том, что намного проще создать декартовский продукт с неявными объединениями. С явным JOINs вы не можете "случайно" создать его. Чем больше таблиц задействовано, тем выше риск того, что вы пропустите одно условие соединения.
  • В принципе (+) сильно ограничен по сравнению с ANSI-соединениями. Кроме того, он доступен только в Oracle, тогда как синтаксис соединения ANSI поддерживается всеми основными СУБД
  • SQL не будет работать лучше после перехода на синтаксис ANSI - это просто другой синтаксис.
  • Oracle настоятельно рекомендует использовать более гибкий синтаксис соединения предложения FROM, показанный в предыдущем примере. Раньше были некоторые ошибки с синтаксисом ANSI, но если вы идете с последними 11.2 или 12.1, которые должны быть исправлены уже.
  • Использование операторов JOIN гарантирует, что ваш код SQL соответствует требованиям ANSI и, таким образом, позволит более легко переносить внешнее приложение для других платформ баз данных.
  • Условия соединения имеют очень низкую избирательность по каждой таблице и высокую селективность по кортежам в теоретическом кросс-продукте. Условия в заявлении where обычно имеют гораздо более высокую избирательность.
  • Oracle внутренне преобразует синтаксис ANSI в синтаксис (+), это можно увидеть в разделе "Информация о предикате" плана выполнения.
1

Я использую (+) нотацию, потому что на этом основаны почти все запросы Oracle, связанные с r12. Я не видел ни одного SQL-запроса со стандартным выражением "join" в запросах Oracle APPS (даже тех, которые предоставлены самим Oracle). Если вы мне не верите, просто перейдите по любой информации, связанной с приложениями Oracle. Например: Запросы, связанные с основными средствами

1

Обозначение Oracle (+) используется только в Oracle, специально для поставщика. И ANSI, стандартная запись регистрации может быть использована в любой СУБД (например, Sql Server, MySql и т.д.). В противном случае нет разницы между нотами Oracle (+) и стандартными нотами объединения ANSI.

Если вы используете стандартную запись регистрации ANSI в своем Sql Query, вы можете использовать тот же запрос в любой СУБД. И, если вы портируете вашу базу данных от Oracle к любой другой RDBMS в этом состоянии вам нужно использовать синтаксис ANSI.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню