
Oracle SQLチューニング Season2(第19回) 第4章 SQL TuningとHINTの関係 (2/8)
「 SQL TuningとHINTの関係 」の第2回目、「 HINTの種類と使い方 」についてお送りしていきます。
「HINTの種類と使い方」については、全6回シリーズで解説していきますが、今回はその1回目をお届けします。
4.2 HINTの種類と使い方(1/6) – 結合順序に関するヒント・結合方式に関するヒント –
SQLの性能問題は、結合順序の異常や間違った結合方法、そして間違ったデータアクセスなど様々な問題が発生します。
このような様々な性能問題を改善するための方法の一つとして使用されるヒントは、オプティマイザに作成者の意図を伝えて効率的な実行計画を策定できるようにします。
そのため、Oracleは様々な性能問題を改善できる方法でSQLの様々な制御をすることができる多くのヒントを提供しています。
したがって、パフォーマンス問題のタイプに最も適したヒントを適用するためには、どのようなヒントがあるかを知る必要があります。
それぞれのヒントがどのように実行されるかを明確に理解していなければ、適切に使用することができないからです。
この章では、よく使われるヒントとOracle 11gに新しく追加されたヒントについて説明します。
この章に記載されていないヒントについては、Oracle Manualを参照するようにしてください。
Script.各テストで使用するスクリプト
4.2.1 結合順序に関するヒント
結合順序とは、SQL内にあるテーブルの実行順序を意味します。
このような結合順序は、SQLの性能問題タイプの中で多くの割合を占めるので、SQLにヒントを適用する時、最も重要です。
結合順序を制御するヒントは ORDERED と LEADING ヒントがあります。
ORDEREDはジョイン順序をFROM節にリストされたテーブルの順序で実行したいときに使用し、LEADINGはヒント構文の中にリストされた入力値の順序でジョイン順序を制御したいときに使用します。LEADINGは10g以前は、最初に実行するテーブル一つだけを指定することができましたが、10g以降のバージョンからは複数のテーブルに対して結合順序を制御できるように変更され、より便利な使用が可能になりました。一方、ORDEREDはプログラムのメンテナンス時にFROM節にリストされたテーブルの順序が最初のヒントを適用した時と異なる場合、SQLの性能問題が発生する可能性があるので注意が必要です。 したがって、10g以降のバージョンからは一般的に結合順序を制御するヒントとしてLEADINGヒントを使用するのがより安定した方法です。
・ORDERED
使用バージョン:8.1.0〜。
使用方法: /+ ORDERED */ /+ ORDERED
ヒントの意味:FROM節にリストされた順番で結合順序を誘導するヒント。
FROM節にリストされた順序が結合順序になるので、最初のSQLにヒントを適用する時の順序が維持(FROM節のテーブルの順序)され、SQLが変更された場合、SQLに適用されたヒントが効率的かどうかを必ずチェックしなければなりません。
・リーディング
使用バージョン:8.1.6〜。
使用方法: /+ LEADING(T1) */ または /+ LEADING(T1 T2 T3) */ 使用方法
ヒント意味:Driving Tableを指定するヒント
10gから /*+ LEADING(T1 T2 T3) */ のように複数のテーブルの順序を制御できるようになり、OREDREDヒントの代わりにLEADINGヒントで結合順序をより簡単に調整することができます。
そのため、10g以降のバージョンでは、結合順序を制御するヒントとしてほとんどLEADINGを使います。
4.2.2 結合方式に関するヒント
テーブル間のジョインをどのような方法で行うかをヒントで決めることができます。
ジョイン方式は、代表的にNested Loops Join、Hash Join、Merge Joinがあり、これを制御するヒントとしてそれぞれUSE_NL、USE_HASH、USE_MERGEがあります。
SQLチューニング時、ジョイン方式を制御するヒントだけを適用する場合、チューニングした時点のジョイン順序が変更される危険性があるので、ジョイン順序を決定するヒント(ORDERED, LEADING)と一緒に適用できるようにしなければなりません。
各ジョイン方法の詳細については、すでに複数のコンテンツで説明されているので、本章では説明を省略します。
・USE_NL
使用バージョン:8.1.0〜。
使用方法: /+ USE_NL(T2) */ または /+ USE_NL(T1 T2) */ を使用します。
ヒントの意味:テーブル間ジョイン方式をNested Loops Joinに誘導するヒント
USE_NLヒントを使用すると、二つのテーブル間の結合方式は、先行テーブルから抽出した件数だけ後行テーブルが繰り返し実行するNested Loops Join方式でSQLが実行されます。Nested Loops Joinは後行テーブルの実行回数とインデックスの効率性によってSQLの性能が左右されるので、下記の二つの場合に使用することが効率的なSQLの性能を誘導することができます。
- 後行テーブルのジョイン接続カラムにインデックスが存在しなければなりません。インデックスが存在しない場合、後行テーブルを先行テーブルから抽出した件数(結合件数)だけTable Full Scanを実行する非効率が発生します。
- Nested Loops Joinは後続テーブルのインデックスから抽出したデータでテーブルアクセス時に発生するRandom I/O量が多い場合、性能が急激に落ちるという欠点があります。従って、後行テーブルが持つ定数条件で実行する方が有利な場合は、USE_HASHヒントを使う方が有利です。また、ジョインされるデータ件数(先行テーブルから抽出したデータ)が少ない場合に有利です。
下記の使用例の内容は、DBMS_XPLAN.DISPLAY_CURSORの内容の一部データです。
・ USE_HASH
使用バージョン:8.1.0〜。
使用方法: /+ USE_HASH(T2) */ または /+ USE_HASH(T1 T2) */ を使用します。
ヒントの意味テーブル間のジョイン方式をHash Joinに誘導するヒント
T2テーブルから抽出されたデータでHash Tableを作成し、T3テーブルのデータでProbeしてデータを抽出します。
後行テーブルがNested Loops Joinで実行されるよりHash Joinが効率的な場合は、通常、先行テーブルからデータが多く抽出され、結合される後行テーブルにアクセス量が多い場合と、後行テーブルの結合カラムに効率的なインデックスが生成されていない場合が代表的な例です。
・ USE_MERGE
使用バージョン:8.1.0〜。
使用方法: /+ USE_MERGE(T2) */ または /+ USE_MERGE(T1 T2) */ を使用します。
ヒントの意味:テーブル間の結合方式をMerge Joinに誘導するヒント
テーブル間または結合結果セットとテーブルの結合方式をMerge Joinに誘導するヒントです。
一般的にMerge JoinよりHash Joinが性能上有利なので、あまり使われません。
・ SWAP_JOIN_INPUTS
使用バージョン:8.1.0〜。
使用方法: /*+ SWAP_JOIN_INPUTS(T1) */ (Inverse: NO_SWAP_JOIN_INPUTS)
ヒント意味: Hash Joinで実行される Outer Join Tableを先に実行する場合に使用するヒント。
Outer Joinを実行するように作成されたSQLの結合順序はすでに決定されています。
もし、既に決められた結合順序を変更したい場合は、SWAP_JOIN_INPUTSヒントを使うことを検討します。
下記のSQLはT1テーブルが先行テーブルになり、T1テーブルとT2テーブルはHash Joinで実行されるSQLです。
Hash JoinもNested Loops Joinのようにデータ件数が少ないセットが先行テーブルとして指定することが有利です。
したがって、Outer Joinを実行しなければならない二つのセット間のデータ数を比較して、Probeテーブルを先行テーブルに
変更することが性能上で有利かどうかを判断した上でヒントを適用すればよいのです。
次回のSQLチューニングブログは
SQLチューニングブログ 2nd Season (第4章)
「SQL Tuning と HINTの関係」(3/8) HINTの種類と使い方(第2回)