web-dev-qa-db-ja.com

Oracle Joins-従来の構文とANSI構文の比較

プリアンブル

最近、「(+)演算子を使用せず、JOIN構文を使用する」というOracleの質問にコメントするオタクが多すぎます。

質問

両方ともうまくいくと思います。しかし、それらを使用することの本当の違いは何ですか?経験からの回答を歓迎します。

 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 [〜#〜]:グループ化されたすべての更新の回答の要約を読み取ります。

28
SriniV

回答をグループ化する

  1. 暗黙的ではなく明示的なJOINを使用すると(外部結合であるかどうかに関係なく)、暗黙的な結合を使用してデカルト積を誤って作成しやすくなります。明示的なJOINを使用すると、「誤って」作成することはできません。関係するテーブルが多いほど、1つの結合条件を見逃すリスクが高くなります。
  2. 基本的に(+)はANSI結合と比較して厳しく制限されています。さらに、ANSI結合構文はすべての主要なDBMSでサポートされていますが、Oracleでのみ使用可能です
  3. ANSI構文への移行後、SQLのパフォーマンスは向上しません。これは単なる構文です。
  4. 前の例に示した、より柔軟なFROM句の結合構文を使用することを強くお勧めします。過去にはANSI構文にいくつかのバグがありましたが、最新の11.2または12.1を使用している場合は、すでに修正されているはずです。
  5. JOIN演算子を使用すると、SQLコードがANSIに準拠するようになり、フロントエンドアプリケーションを他のデータベースプラットフォームに簡単に移植できるようになります。
  6. 結合条件は、各テーブルで非常に低い選択性を持ち、理論上のクロス積のタプルで高い選択性を持ちます。 whereステートメントの条件は、通常、選択性がはるかに高くなります。
  7. Oracleは、ANSI構文を内部的に(+)構文に変換します。これは、実行プランの述語情報セクションで確認できます。

12cエンジンでANSI構文を使用する場合の落とし穴

12cのJOINにバグの可能性を含める。 こちら をご覧ください

フォローアップ:

Quest SQL optimizer toolは、SQLをANSI構文に書き換えます。

9
SriniV

200個以上のパッケージが「昔ながらの」構文で意図したとおりに機能する場合は、そのままにしてください。 ANSI構文への移行後、SQLのパフォーマンスは向上しません。これは単なる構文です。

とはいえ、ANSI構文はよりクリーンです。複数列の外部結合で(+)を忘れると、通常の結合になりません。
過去にはANSI構文にいくつかのバグがありましたが、最新の11.2または12.1を使用する場合は、すでに修正されているはずです。
もちろん、あなたは環境と優先順位をよく知っています-SchmitzITが述べたように、ANSI構文はSQL標準の一部であり、他のRDBMS製品を使用するときに役立ちます。

24
igr

11gでは、ANSI結合構文を使用する必要があります。より柔軟で(完全外部結合とパーティション結合のサポート)、ドキュメントに次のように記載されています。

前の例に示した、より柔軟なFROM句の結合構文を使用することを強くお勧めします。

それが十分な理由です。

14
David Aldridge

他の人が述べた理由とは別に、JOIN演算子を使用すると、SQLコードがANSIに準拠するようになり、フロントエンドアプリケーションを他のデータベースプラットフォームに簡単に移植できるようになります。

5
SchmitzIT

実際には、常にANSI構文を使用する必要があります。パッケージと手順をやり直さないでください。むしろ、これらのスクリプトを個別にメンテナンスするときに修正することができます。構文による計画の違いはありません。

Quest SQLオプティマイザーは、考えられるすべての組み合わせで書き直し、より良い計画を見つけます。そのため、100を超える結果から1つのSQLを検索する必要があります。

4
user4223622

選択性に基づいた述語の分離

クエリを結合条件に分離し、条件がオプティマイザーに追加のヒントを提供できる場合。結合条件は、各テーブルで非常に低い選択性を持ち、理論上のクロス積のタプルで高い選択性を持ちます。 whereステートメントの条件は、通常、選択性がはるかに高くなります。

左側の各行の結合条件では、右側に値が存在する可能性が非常に高くなります(逆も同様です)。そのため、このような条件は2つのテーブルからの結果を結合するのに適していますが、結果セットから個々のテーブルから値を削除するのにはあまり役立ちません。

通常、where句の条件を使用して、結果セットから1つのテーブルから個々の行を削除できます。

(人間!)オプティマイザーのヒント

したがって、個々のテーブルのwhere条件を最初に実行し、結果セットから可能な限り多くの行を削除するのは良い戦略です。その後、結合条件を使用して、残っている行を結合できます。

Oracleオプティマイザーが、クエリを最適化するためのヒントとしてSQLステートメント内の条件の位置を実際に使用しているかどうかは明らかではありません。テーブル統計の難しい事実にもっと興味があると思います(11g R1でOracleが異なる結合を処理する方法にいくつかの変更がありました。詳細については、Oracleオプティマイザーチームの この投稿 を参照してください)。

少なくとも人間としての私にとっては、クエリを理解して最適化しようとするときに、ステートメントが単一テーブルに対して選択性を持っているかどうかを知ることは非常に役立ちます。 ON句に複数の条件を指定する場合も、これを考慮する必要があります(例:ON (a.x=b.x AND a.y=b.y)vs. where clasueに条件の1つを配置する:条件がどの程度選択的であるかを確認します。

結論

既存のクエリについては、構文をそのままにしてください。新しいクエリを作成するとき、または既存のクエリをリファクタリングするときは、「JOIN ON」構文を使用して選択性の述語をソートしてみてください。単一のテーブルで選択できない場合は、ON部分に配置します。

4

外部結合で使用される(+)記号は、外部結合のOracle構文です

信頼できるOracleソースから収集した情報から、200以上のパッケージがあり、内部的にはOracleがANSI構文からOracle構文に変換するため、既存のパッケージのOracle外部結合構文を保持できることがわかりました。

Using(+)演算子に制限がある場合は、今後ANSI構文をご利用ください

(+)サイン外部結合の詳細な説明のリンクを見つけてください。これは、移行の決定に役立ちます。

Oracle外部結合構文およびANSI構文

(+)外部結合の使用の制限

Oracle外部結合の詳細

(+)Java)で推奨される外部結合演算子

3
psaraj12

一部の解説者は、(+)構文では完全な外部結合を許可しないと述べています。これは問題ではないので、これは問題ではありません:(LEFT OUTER JOIN)UNION ALL(RIGHT OUTER JOIN)。

他の人は、パフォーマンスが切り替えを行う理由だと言っています。これは、特にSQLのBSの束です。もちろん、いくつかのガイドラインがありますが、すべてのクエリとすべてのデータベースには独自の特性があるため、一般的な状況ではなく特定の状況に合わせて調整する必要があります。

標準ではないことに加えて、(+)から切り替える理由は、新しい明示的な構文とは対照的な制限です。 http://docs.Oracle.com/cd/E16655_01/server.121/e17209/queries006 .htm#SQLRF52354 。ここから読み始めてください:「Oracleの結合演算子ではなく、FROM句のOUTER JOIN構文を使用することをお勧めします。」

2
itmitica

仕事の経験から言えば、(+)の代わりにJOINを使用する方が、ソリューションでの作業がより簡単、高速、見栄えが良く、特に複数データベースの選択(類義語全体)で作業する場合、大きなデータベース(1000以上のテーブル、20億行以上のテーブルがある)に多くのテーブル(例:40以上のテーブル)があると、大きな違いを感じるでしょう。

2
Ján Srniček

異なるプロジェクトで両方のアプローチを使用しましたが、JOIN構文を好みます。

  • ON句の結合条件とWHERE句のフィルター条件には明確な分離があります。
  • 多数の結合を使用して大規模なクエリを読み、保守するのが簡単です。
2
Nazarii Bardiuk