
Oracle SQLチューニング(第15回)「スカラーサブクエリの理解と効率的なSQLの作成」(5/5)
今回は、スカラーサブクエリと結合に関しての2回目・スカラーサブクエリの理解と効率的なSQLの作成の最終回です。
3.1.2.2 スカラーサブクエリと結合の関係から見るSQL性能問題
以下の二つのSQL中SCALAR_SQL[1]はFrom句にSCALAR_T1テーブルだけ指定し、SCALAR T2,SCALAR_T3テーブルはスカラーサブクエリを使うように作成した。 また、SCALAR SQL[2]はSCALAR_T1,SCALAR_T2,SCALAR_T3テーブルを全部結合した後データを抽出するようにSQLを作成した。
一般的にSQLを作成する時ある作成方法が性能上有利かを知ることができる公式は存在しない。 しかし処理データ量、テーブルやカラムの制約条件、インデックス構成有無などを考慮しなかったSQL作成は性能問題を発生させることがあるので注意しなければならない。
以下の例題を通じてSCALAR_SQL[1]とSCALAR_SQL[2]がどんな状況で性能問題が発生するのか、そして発生した性能問題をどのように改善するのが効率的なのか調べてみる。
① SCALAR_SQL[1]およびSCALAR_SQL[2]のSQL説明および改善方向の導き出し
(1) SCALAR_SQL[1] SQL説明
(2) SCALAR_SQL[2] SQL説明
SCALAR_SQL[1]とSCALAR_SQL[2]のトレース結果を見れば、二種類の方法とも性能問題を有している。 したがってSCALAR_SQL[1]とSCALAR_SQL[2]の性能問題を解決できる方法に対して調べてみる。
② 非効率スカラーサブクエリは結合に変更しよう
一般的に配置プログラム(多くのデータ抽出)はスカラーサブクエリを使わないようにSQLを作成することが性能に有利な場合が多い。 SCALAR_SQL[1]の場合SCALAR_T1テーブルのすべてのデータを抽出(50万件)し、SCALAR_T2、SCALAR_T3テーブル照会をスカラーサブクエリで実行するようにSQLが作成されている。 したがってSCALAR_T2とSCALAR_T3のインデックスを実行する回数が抽出データと同一となり、50万回ずつ実行(C1カラムはUnique値を有している)して性能問題を発生させている。
このように最終抽出件数が多くて、スカラーサブクエリ実行回数が多い場合、スカラーサブクエリをOuter Joinに変更して、Hash Joinに変更すれば性能を改善することができる。
ただし、スカラーサブクエリを結合に変更する時は以下の制約事項を必ず守らなければならない。
- 制約事項1 : Outer Joinに変更する(常に結合に成功するならばOuter Joinで処理しなくても関係ない).
- 制約事項2 : スカラーサブクエリをOuter Joinに変更した後、結合連結カラムの値はUniqueでなければならない。
それでは、SCALAR_SQL[1]の[改善前SQL]と[改善後SQL]のSQLとそれぞれのトレース結果を確認してみよう。
Note : 繰り返し実行されたスカラーサブクエリをOuter Joinに変更した後、Hash Joinで処理してインデックスに対する反復的な探索が除去されて性能が改善された。
③ 結合をスカラーサブクエリに変更しよう
今までの内容を見れば、あたかもSQL性能のためにはスカラーサブクエリを使ってはいけないように感じる。 それで以下のような質問に対してはどうだろうか?
Q : "常にスカラーサブクエリを使うのは不利なのか?"
A : "違う。 スカラーサブクエリを使うことが有利な時もある。"
Q : "そのような場合はいつか?"
この質問に対する答えを探すために、まず以下の[改善前SQL]のSQL方式とトレース結果を先に見ることにしよう。
[改善前SQL]はSCALAR_T1,SCALAR_T2,SCALAR_T3テーブルの結合を処理したデータを整列して、ROWNUM <= 10条件で最終データを10件抽出する。 ところでSCALAR _T2とSCALAR_T3テーブルは抽出データに比べてとても多くのI/O処理量で実行されている。 その理由はSQLにUSE_NL(T1 T2 T3)ヒントがあってNested Loops Joinで実行されるが、最終10件を抽出する前に処理するデータがとても多く、反復的なインデックス スキャンによりI/O処理量が大量に発生したのである。 したがってNested Loops Join代わりにHash Joinで実行するように、ヒントをUSE_HASH(T1 T2 T3)に変更すればSQLの性能が改善されることを予想することができる。 次の[改善後SQL]のヒント適用SQLとトレース結果を確認してみよう。
[改善前SQL]に比べて性能が非常に改善された。 ところが最終抽出データが10件に過ぎいが、まだSCALAR_T1 ~ SCALAR_T3テーブルの全体データを処理するので非効率が相変らず存在している。
反面、[改善後SQL]のSCALAR_T2とSCALAR_T3テーブルはOuter Joinで実行されて、結合連結カラムのデータがUniqueとなるので、SCALAR_T1で10件を抽出した後実行するように変更してもデータの完全性を影響なく、SQLの性能を改善すると予想される。
この場合[改善前SQL]の性能を改善するために、SCALAR_T2とSCALAR_T3を最終抽出データである10件に対してだけ実行されるように変更しなければならない。 このような改善方法は大きく二種類がある。 一番目の方法は、SCALAR_T1で10件抽出後、SCALAR_T2とSCALAR_T3テーブルをNested Loops Joinで実行するように変更することである。 そして二番目の方法は、最初の方法のNested Loops Join代わりにスカラーサブクエリでに変更することである。
[改善前SQL]に対する改善方法で、二つの方法ともに使えるが、以下の四種類条件を満足するSQLは結合よりスカラーサブクエリが効率的だと考える。
- 最終抽出件数が少なくて最終抽出件数回実行しても性能上問題がない。
- テーブル結合がOuter Joinで、結合連結カラム値の種類が少ない。
- WHERE節の条件もOuterで抽出データに影響を及ぼさない(例:T2.C2(+) = ‘A’).
- テーブルの実行位置を変えてNested Loops Joinに誘導するのが難しい場合(例:インライン ビュー内でグルーピングを実行するSQL).
もちろん、[改善前SQL]の性能改善方法で二つの方法ともに適用できるが、この章ではスカラーサブクエリーに対する内容を扱うので、SCALAR_T2,SCALAR_T3をスカラーサブクエリでに変更して性能を改善してみるようにする。
Note.スカラーサブクエリと結合の使用基準
[1]抽出データが少ない場合(オンライン プログラム)? スカラーサブクエリ使用OK!
→ 結合をスカラーサブクエリでに変更するのを考慮
[2]抽出データが多い場合(バッチプログラム)? スカラーサブクエリ使用NO!
→ スカラーサブクエリを結合に変更後Hash Joinで実行するのを考慮
④ スカラーサブクエリの結合連結条件にはTable Aliasを必ず指定しよう
スカラーサブクエリは普通From句のテーブルとの結合条件が存在するが、この時、連結条件で使われた二つのカラム名が同じ場合ならば、Table Aliasを必ず明確に指定しなければならない。 なぜならAliasを指定しない場合、結合条件で使おうとしていた本来の意図とは違ってサブクエリ内で単独条件で実行されて、深刻な問題が発生する可能性があるためである。
例えば、スカラーサブクエリの結合条件が“id = id”であるが、Aliasを指定しないならば、サブクエリ内の自身のカラムと比較をすることになる。 したがって実際的には“id is not null”条件と解釈されることになる。 この場合スカラーサブクエリ内に“id = id”と結合接続条件のほか、他の効率的な条件がないならば、深刻な性能問題を誘発することになる。
実際の事例を通じて調べてみる。
[性能問題SQL]はスカラーサブクエリのT_IME01MTテーブルがFull Table Scanで実行されて非効率が発生している。 まずスカラーサブクエリがなぜFull Table Scanで実行されたのか点検してみよう。
Full Table Scanに影響を及ぼす要件
- 発生要因[1]: 結合連結条件のデータ タイプ不一致
- 発生要因[2]: 結合カラムに適切なインデックスが存在しない
発生要因[1]を点検してみれば、結合連結条件のカラムであるSEEDSEQはスカラーサブクエリのテーブルとFrom句のテーブルに存在し、データ タイプはNUMBERで同一である。 したがってデータ タイプ不一致によるFull Table Scanはない。
発生要因[2]を点検してみれば、スカラーサブクエリテーブルであるT_IME01MTにXIE2T_IME01MTインデックスが存在する。 したがって適切なインデックスが存在せず発生するFull Table Scanはない。
それならスカラーサブクエリのT_IME01MTテーブルはなぜ Full Table Scanで実行されたのだろうか? その理由はOptimizerが[性能問題SQL]を以下のように解釈したためである。
すなわちオプティマイザがスカラーサブクエリの結合条件であるSEEDSEQ値がFrom句のT_ISE01MTテーブルのSEEDSEQ値でないスカラーサブクエリT_IME01MTテーブルのSEEDSEQ値と解釈することによって、内部的にA.SEEDSEQ IS NOT NULLで処理され、これによってFull Table Scanで実行されたのである。 この性能問題はSQL自らの解釈が変わってデータ完全性まで毀損することがあるのでスカラーサブクエリ作成する時留意しなければならない。それでは、SQL作成意図に合うようにスカラーサブクエリの結合連結条件にTable Aliasを追加した後SQLの性能を確認してみよう。
前のトレース内容を見れば、スカラーサブクエリで処理したデータが多いが(SEEDSEQ,STATUSから抽出されるデータが多いこと) Index Range Scanで実行され、I/O発生量も119ブロックで正常なインデックス スキャンで処理されたということがわかる。 このようにスカラーサブクエリ作成時ささいな失敗(Table Alias脱落)が深刻な問題を起こすことがあるということに対して調べてみた。 したがってスカラーサブクエリを作成する時結合連結カラムに対して必ずTable Aliasを明示してSQLを作成するようにしなければならない。
今までスカラーサブクエリーによる性能問題と各性能問題に適合した改善法案に対して調べてみた。 スカラーサブクエリの性能問題はスカラーサブクエリの特性を理解して、SQLパターンに合うようにスカラーサブクエリを結合で、結合をスカラーサブクエリでに変更することになじんでこそ性能に最も有利な改善方法を導き出すことができた。 したがってこれらの記述した内容を理解して、多様な類型のSQLに応用してみるように願う。
いかがでしたでしょうか?今回で第3章「スカラーサブクエリの理解と効率的なSQLの作成」は終了となります。次回からは、第4章「WITH節理解と効率的なSQLの作成」になります。ご期待ください。
See you ^^