L
o
a
d
i
n
g
.
.
.

ホーム

お知らせ

製品・ソリューション

サービス

導入事例・パートナー

EXEM Academy・ブログ

会社情報

採用情報

2024.12.24

SQLチューニング 2nd Season(第25回) 第4章 SQL TuningとHINTの関係 (8/8)

今回のSQLチューニングブログ 2nd Season(第25回)は、「SQL TuningとHINTの関係」の最終回です。
~ HINTの適用と注意事項 ~ について解説していきます。

それでは早速、はじめていきましょう。

 4.3 HINTの適用と注意事項

4.3.1 HINTを適用する

SQLに性能問題が発生し、DBサーバー全体に負荷を発生させる状況は頻繁に起こります。
このような悪質なSQLに対する対処方法は、状況によって様々な方法で改善することができますが、最も汎用的で効率的な方法としては、ヒントを適用して素早く問題を解決する方法です。

ヒントを使用してSQLに対する性能改善をするということは、性能問題があるSQLを作成者(業務担当者)、またはDB管理者の積極的な
介入を通じて実行計画をより効率的に調整するということです。
実行計画とSQL Trace分析が可能であれば、簡単かつ迅速に問題が発生した部分への解決策を用意することができるでしょう。

このように、ヒントは性能問題においてかなり強力な存在感を持っています。
これに、以下で紹介するSQLチューニング時に知っておくべきAccess Pathの必須3要素の理解を加えていれば、ほとんどの性能問題を持つSQLの改善作業をより簡単に解決することができます。

SQLチューニング時に知っておくべきAccess Pathの構成要素

ジョイン順序:SQL実行時、最初に実行されるテーブル(Driving Table)とFROM節テーブル間の結合順序は常に存在します。このような結合順序は、SQLを実行する時、効率的なAccess Pathで実行されるための最も重要な要素です。

結合方法:先行テーブルと後行テーブル間の結合方法、そして先行結果セットと後行テーブルの結合方法を決定することは、SQLの効率的なAccess Pathを誘導するために必要な要素です。

データアクセス方法:データにアクセスする時、どのような方法(Index ScanまたはFull Table Scanなど)で行うかを決定することで、SQLの効率的なAccess Pathを決定するために必ず必要な要素です。また、ジョイン接続カラム(インデックスがあるかなど)についても考慮しなければなりません。

パフォーマンス問題を抱えているSQLを改善には、結合順序、結合方法、データアクセス方法をまずは効率化することが必要です。
なぜなら、オプティマイザが実行計画を作成する際にコスト計算を行う際に考慮する要素だからです。
また、この3つの要素は、ヒントを適用する際に必ずヒントに含めるべき内容でもあります。

ヒントの使用目的は、SQLの効率的な実行計画の生成を誘導することです。
そして、生成された実行計画は他の変数によって再び変更される事を防止しなければならないため、必ず上記3要素をヒントに記載して実行計画を固定しておく必要があります。
つまり、基本的に3つの要素をヒントに記載しておくことで、オプティマイザがヒントの作成者の意図に合致するように実行計画を生成すると同時に維持させることができると言うことを意味します。

もちろん、SQLにビュー、インラインビュー、サブクエリなどSQL内に複数のQuery Blockがある場合には、変数が発生する可能性があります。しかし、ほとんどの場合はジョイン順序、ジョイン方法、そしてデータアクセス方法をSQLにヒントとして指定しておけば、実行計画が変更されるリスクはなくなります。

ではここからは、テストを通じてジョイン順序、ジョイン方法、データアクセスに関するヒントとその使い方について説明していきます。

データAccess Path必須3要素ヒントを適用する方法

以下の例を通じて「データAccess Path必須3要素」に該当するヒントを与えることで、性能改善及び実行計画を固定する一連の過程を見ていくことで、より深い理解に繋げていきたいと思います。

サンプルSQL:


:B1 := ‘2013-01-01’
:B2 := ‘2013-01-31’

SELECT t1.* ,
       t2.* ,
       t3.*
FROM   hint_t1 t1 ,
       hint_t2 t2 ,
       hint_t3 t3
WHERE  t1.cust_name = 'CUST_A'
AND    t3.orddate BETWEEN to_date(:b1,'YYYY-MM-DD')
AND    to_date(:b2,'YYYY-MM-DD')
AND    t1.cust_no = t2.cust_no
AND    t2.cust_no = t3.cust_no;

------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name          | A-Rows |   A-Time   | Buffers | Reads  |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |               |      3 |00:00:03.43 |    1395 |   1384 |
|*  1 |  FILTER                       |               |      3 |00:00:03.43 |    1395 |   1384 |
|*  2 |   HASH JOIN                   |               |      3 |00:00:03.43 |    1395 |   1384 |
|   3 |    TABLE ACCESS BY INDEX ROWID| HINT_T3       |     31 |00:00:00.01 |       4 |      0 |
|*  4 |     INDEX RANGE SCAN          | IDX03_HINT_T3 |     31 |00:00:00.01 |       3 |      0 |
|*  5 |    HASH JOIN                  |               |   6810 |00:00:03.37 |    1391 |   1384 |
|*  6 |     TABLE ACCESS FULL         | HINT_T1       |   3846 |00:00:00.03 |     420 |    415 |
|   7 |     TABLE ACCESS FULL         | HINT_T2       |    300K|00:00:00.82 |     971 |    969 |
------------------------------------------------------------------------------------------------

上記の例にあるSQLとXPLANの結果を見て、非効率が発生した原因は何なのか?について分析を行い、解決するためのヒントを与えてパフォーマンスを改善してみることにしましょう。

 Q:上記の例で発生した非効率の原因は何でしょうか?

実行計画を分析してみると、オプティマイザはORDDATEで範囲条件(2013年1月一ヶ月)が存在するHINT_T3テーブルを一番最初に実行するテーブル(Driving Table)として選定し、HINT_T1、HINT_T2テーブルを順番にHash Joinを実行することが分かりました。
HINT_T1、HINT_T2テーブルのデータアクセス方法は全てTable Full Scanであり、ORDDATE条件が存在するHINT_T3テーブルのみIndex Range Scanで実行しました。
上記の例にあるSQLを実行するために発生した総I/O量は1,395ブロックであり、このうちのほとんどのブロックはHINT_T1、HINT_T2テーブルのデータアクセス方法のTable Full Scanによって発生しました。
そして、HINT_T1とHINT_T2テーブルに対するHash Joinを実行した時間が3.37秒かかりました。

全体のI/O発生量と応答時間のほとんどは、HINT_T1, HINT_T2テーブルをTable Full ScanとHash Joinを実行する部分で発生したものであるため、この部分がまさに非効率の原因であったことを分析することができます。

では、この非効率を改善するためには、どのようなAccess Pathに誘導すればいいのでしょうか?
SQLの性能改善のためにどのようにヒントを与えるべきか見てみましょう。

ジョイン順序

ジョイン順序の決定は、SQLを実行する上で全体的なジョイン回数を決定することができるため、SQL性能全体を左右する入口となってくるため、非常に重要なプロセスです。

それではまず、上記の3つのテーブルの中で一番最初に実行するテーブルを選定してみましょう。

先行テーブルを選定するためには、SQLのWhere節の定数条件に対する分析が必要です。
Where節の条件としてバインド変数が使われたHINT_T3テーブルのORDDATEカラムのBetween条件とHINT_T1テーブルのCUST_NAME条件があります。結合条件を除けば何の条件もないHINT_T2テーブルを除けば、二つのテーブルのうち先行テーブルを決定することができるでしょう。

次に、バインド変数が使われたHINT_T3テーブルのORDDATE条件から見てみましょう。

HINT_T3テーブルのORDDATE条件に該当する全体のデータ件数は31件であることが上記の実行計画例から確認できます。そして、下記のように整理することができます。
元の日付などBETWEEN条件で入力されるバインド変数の値は、照会履歴まで確認して判断する必要がありますが、ここでは実行計画に出たデータだけを使って説明します。

SELECT count(*)
FROM   hint_t1 t1
WHERE  t3.orddate BETWEEN to_date('2013-01-01')
AND    to_date('2013-01-31');

COUNT(*)
----------
        31

・ HINT_T1テーブルのCUST_NAME条件を満たすデータ件数は3846件です。

SELECT count(*)
FROM   hint_t1 t1
WHERE  t1.cust_name = 'CUST_A';

COUNT(*)
----------
      3846

・ Where節の定数条件として最初に実行するテーブルをHINT_T3に決定しました。

ジョイン方法

先行テーブルが決定されたので、次はどのような結合方法で行うかを決定してみましょう。
やはりWhere節の結合条件を見てみましょう。HINT_T1、HINT_T2、HINT_T3テーブルを結合するカラムは全てCUST_NOカラムです。HINT_T1、HINT_T2、HINT_T3テーブルの生成スクリプトをもう一度確認してみると、CUST_NOカラムはNumber of Distinct Valueの面で非常に効率的なカラムであることが分かります。
そして、HINT_T1, HINT_T2のCUST_NOカラムにインデックスが生成されています。従って、先行テーブルから抽出された件数が31件で、HINT_T1, HINT_T2テーブルの変別力に優れたジョインカラムであるCUST_NOカラムに全てインデックスが存在しているので、例のようにテーブル間のジョイン方法がHash Joinではなく、Nested Loops Joinで実行することが効率的な実行になるでしょう。

データアクセス

ジョイン方法をNested Loops Joinに決定し、データアクセス方法も事実上決定しました。
Nested Loops Joinはジョインキーカラムにインデックスが存在しなければ性能が保証されます。
幸いHINT_T1, HINT_T2テーブルにはCUST_NOカラムにインデックスが既に生成されているので、データアクセス方法はIndex Scanを選択すればよいのです。

 

ヒント適用

SQLの性能改善のために’データAccess Path必須3要素’に該当する部分を全て決定しました。
上の例にあるSQLへヒントを適用して性能にどんな変化があるのか?を見ていくことにしましょう。

ヒント適用SQL:


SELECT /*+ LEADING(T3 T2 T1) USE_NL(T1 T2) INDEX(T1 IDX01_HINT_T1) INDEX(T2 IDX02_HINT_T2) */
       t1.*,
       t2.*,
       t3.*
FROM   hint_t1 t1 ,
       hint_t2 t2 ,
       hint_t3 t3
WHERE  t1.cust_name = 'CUST_A'
AND    t3.orddate BETWEEN to_date(:b1,'YYYY-MM-DD')
AND    to_date(:b2,'YYYY-MM-DD')
AND    t1.cust_no = t2.cust_no
AND    t2.cust_no = t3.cust_no;

-------------------------------------------------------------------------------------------------- 
| Id  | Operation                       | Name          | Starts | A-Rows |   A-Time   | Buffers | 
-------------------------------------------------------------------------------------------------- 
|   0 | SELECT STATEMENT                |               |      1 |      3 |00:00:00.01 |     245 | 
|*  1 |  FILTER                         |               |      1 |      3 |00:00:00.01 |     245 | 
|   2 |   NESTED LOOPS                  |               |      1 |      3 |00:00:00.01 |     245 | 
|   3 |    NESTED LOOPS                 |               |      1 |     84 |00:00:00.01 |     161 | 
|   4 |     NESTED LOOPS                |               |      1 |     84 |00:00:00.01 |     152 | 
|   5 |      TABLE ACCESS BY INDEX ROWID| HINT_T3       |      1 |     31 |00:00:00.01 |       4 | 
|*  6 |       INDEX RANGE SCAN          | IDX03_HINT_T3 |      1 |     31 |00:00:00.01 |       3 | 
|   7 |      TABLE ACCESS BY INDEX ROWID| HINT_T2       |     31 |     84 |00:00:00.01 |     148 | 
|*  8 |       INDEX RANGE SCAN          | IDX02_HINT_T2 |     31 |     84 |00:00:00.01 |      64 | 
|*  9 |     INDEX UNIQUE SCAN           | IDX01_HINT_T1 |     84 |     84 |00:00:00.01 |       9 | 
|* 10 |    TABLE ACCESS BY INDEX ROWID  | HINT_T1       |     84 |      3 |00:00:00.01 |      84 | 
--------------------------------------------------------------------------------------------------

結合順序と結合方法、データアクセス方法に対するヒントを適用すると、応答時間、I/O発生量ともに大幅に改善された結果が出ました。SQLに適用したヒントは下記の通りです。

・ 結合順序 : LEADING(T3 T2 T1)
・ 結合方法 : USE_NL(T1 T2)
・ データアクセス方式 : INDEX(T1 IDX01_HINT_T1) INDEX(T2 IDX02_HINT_T2)
Q:でもナゼ、そんなに複雑にヒントを適用する必要があるのですか?

なぜなら、ヒントを適用するのは、SQLに対する業務把握が完了した状況で行うものであり、ヒントを適用したSQLの実行計画を固定しなければ性能を維持することができないからです。 また、SQLの実行計画を固定するためには、結合順序、結合方法、データアクセス方法を正確に指定しなければなりません。

上にある質問は、SQLチューニングに関するコンサルティングを行う時によく質問として受ける内容です。
そしてすぐ下の答えは、質問者である顧客担当者に返答する内容であり、筆者である私の考えでもあります。

ここで、

一つ追加で説明する部分は、SQLにORDDATEと同じ範囲条件です。
例では2013年1月に該当する期間に限定しましたが、もし期間条件のバインド変数の値が1年またはデータ全体に該当する期間が入力される場合はどうでしょうか?

データ全体に該当するバインド変数が入力される場合、HINT_T3テーブル全体の件数である25万件に相当するIndex Scanとそれに対応するNested Loops Joinの実行で、パフォーマンスは既存の例のHash Joinで実行されたときよりも不利になります。したがって、このような場合には、必ずバインド変数の最大入力期間がどうなるかを考慮する必要があります。これを考慮せずに上記のヒントを適用することは、常にすべての場合で性能上有利な結果を保証することができないのがその理由です。ですので、SQLの性能改善方法としてヒントを適用する場合は、SQLに対する業務把握が完璧になった時点であることを覚えておきましょう。

前述のように、パフォーマンスを改善するためにヒントをどのように適用すべきかを知ることも重要ですが、適用したヒントは実行計画を常に固定することを意味するため、発生する可能性のある様々な変数に対する十分な検証が必要です。

 

4.3.2 Hint 使用時の注意事項

実行計画が変更されないこと

SQLの実行計画が変更されるケースはいくつかあります。
先ほど紹介したBind Peeking機能の使用、Bind変数をモニタリングしてこれによる実行計画の変更が必要な場合に変更するAdaptive Cursor機能の使用、SQLに含まれるテーブルまたはインデックスの統計情報の生成および更新、関連パラメータの変更など、影響を与える可能性があるものはたくさんあります。

性能問題を改善するためには、上記の要素とは関係なく、常に固定的な実行計画で実行しなければならないSQLには、ヒントを通じて実行計画の固定を図ることができます。

ヒントについて説明する際に、チューナーの積極的な介入という表現を使ったことがあります。
これは、実行計画を生成するオプティマイザの一連の過程と判断を排除したチューナーの判断に合った実行計画で実行するという意味でもあります。例えば、FROM節に10個のテーブルを結合するSQLがあるとします。チューナーが常に最初に実行されるべきテーブルを /*+ LEADING(A) */ ヒントだけを適用した場合、すべての場合、チューナーの意図通りにSQLが実行されるでしょうか?

その結果は誰にもわからないのです。ただ一つ確かなことは、常にAテーブルが先に実行されるということだけです。残りの9つのテーブルのジョイン順序とジョイン方法はどのように実行されるか分からないという意味です。Aテーブルが常に先行テーブルになったとき、残りの9つのテーブルの結合順序、結合方法と関係ないほど性能に大きな問題がないと判断される場合を除き、チューナーが/*+ LEADING(A) */ヒントだけを適用して最適な実行計画を生成したとしても、これを適用したSQLがチューナーが実行したそのままの実行計画で常に実行されるのか確信することは難しいことです。 したがって、ヒントを適用するときは、先に説明したSQL Access Path 3要素に対するヒントをすべて記載するのが良いのです。

開発環境でインデックスヒントを使うときは注意しよう

運用環境でSQLの性能問題を解決するために必ずインデックスヒントを適用しなければならない場合がありますが、一般的にオプティマイザが効率的な実行計画を策定するため、インデックスヒントを乱発してはいけません。 なぜなら、インデックスヒント構文の中に記述されたインデックスが削除または名前が変更されると、Oracleはそのヒントを無視して実行計画を生成するからです。したがって、開発プロジェクト時(開発環境)にSQLに必ずインデックスヒントを適用しなければならない場合には、DBAと協議の上、運用環境のNaming Ruleを必ず守らなければなりません。開発環境と運用環境のNaming Ruleが異なる状況でヒントを適用することは意味がないだけでなく、予期せぬ性能問題の原因になる可能性があるからです。

データ変更が激しい場合はヒント使用に注意しよう

例えば、製造会社の特定製品の販売実績を実行する下記のようなSQLがあるとします。

SELECT product_nm 製品名,
       SUM(price) 販売額
FROM   product
WHERE  dt BETWEEN TO_DATE( :b1 , 'YYYY-MM-DD' )
AND    TO_DATE( :b2 , 'YYYY-MM-DD' )
AND    plant_code = :b3
AND    product_code = :b4
GROUP  BY product_nm

上記SQLの性能問題でこれを改善するためにチューナーがDBMS_XPLAN結果などを活用して、PROODUCT_CODEカラムにインデックスを生成し、そのインデックスを使用するためにインデックスヒントを適用して反映されました。ところが、時間がある程度経過した後、当該SQLの性能問題が再発しました。性能問題を分析してみると、ヒントの適用部分が問題になったのです。確かに、最初のチューニング時は効率的だったのに、なぜ、時間が経った後、SQLに性能問題が発生したのでしょうか? その理由は、当該テーブルのデータ特性が変更されたからなのです。販売初期段階では、当該製品(PRODUCT_CODE)の販売量が多くない場合があります。販売された量が少ないので、そのカラムにインデックスを生成してIndex Scanを誘導するようにヒントを適用させると、その時点では良好な性能を見せることが予想できます。しかし、時間が経つにつれ、そのPRODUCT_CODE製品の販売量は継続的に増加するでしょうし、もしその製品がヒット商品になれば、データ照会件数が急激に増えるので、パフォーマンスは徐々に悪化するでしょう。

性能改善作業を行う際に、データの性質を事前に把握していない状況で、安易な判断でヒントを適用させることは危険な状況を招く可能性があります。データが今後大きく変更される可能性があるかどうか、業務に対する理解なしにヒントを適用することは、単にSQL Tuning作業を行っただけで、DBサーバー全体の性能改善作業を行ったわけではありません。厳密に言えば、むしろDBサーバーの性能を悪化させることができる潜在的な要素を再現した意味のない行為になる可能性があります。

簡単な作業、SQLでも含まれている主要カラムの性質を常に確認する習慣を持つと、上記のようなエラーを犯さないことができます。

ヒントが適用されたプログラムのメンテナンス時に注意しよう

SQLが頻繁に変更されるのは、業務が頻繁に変更される事が原因です。このようなSQLに対しては、ヒントを適用することは逆に不適切となる場合があります。SQLの変更を担当する開発者が、既存のSQLに適用されたヒントの内容を見てこれをきちんと理解した上で、それに合わせたSQLを作成したり、ヒントを再調整することができるのであれば、特に大きな問題にはありませんが、現実的には難しいことでもあります。

このような場合では、変更されたSQLによって再び性能改善作業を進めるか、ヒントを適用する以外の方法でSQLの性能問題を改善できるか?について確認する必要があります。

動的WHERE節を持つSQLにヒントを適用する時は注意しましょう。

動的なWhere節を持つSQLに業務に対する理解なしにヒントを適用するのは非常に危険です。

以下の例を見てみましょう。

性能問題SQL:


SELECT /*+ FULL(T3) */
       COUNT( * )
FROM   HINT_T3 T3
WHERE  1 = 1
AND    GOODS_NO BETWEEN '1' AND '100'
AND    ORDDATE BETWEEN TO_DATE('2013-01-01','YYYY-MM-DD') AND TO_DATE('2013-01-31','YYYY-MM-DD');

-------------------------------------------------------------------------------------------------
| Id  | Operation          | Name    | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |         |      1 |        |      1 |00:00:00.14 |   10511 |  10507 |
|   1 |  SORT AGGREGATE    |         |      1 |      1 |      1 |00:00:00.14 |   10511 |  10507 |
|*  2 |   TABLE ACCESS FULL| HINT_T3 |      1 |      1 |      1 |00:00:00.14 |   10511 |  10507 |
-------------------------------------------------------------------------------------------------

[ HINT_T3 테이블 Index 정보 ]

INDEX_NAME                               COLUMN_NAME                             
---------------------------------------- ----------------------------------------
MAXGAUGE.IDX01_HINT_T3                   ORD_NO                                  
                                         GOODS_NO                                
                                         ORDDATE                                 
MAXGAUGE.IDX02_HINT_T3                   CUST_NO                                 
MAXGAUGE.IDX03_HINT_T3                   ORDDATE

上記の例のSQLを分析してみると、すでにヒントに /*+ FULL(T3) */ ヒントが固定されており、Where節の条件で1件を抽出するため、HINT_T3テーブルの全体サイズ分(約1万ブロック分)のI/Oが発生する非効率があります。これを改善するためにHINT_T3テーブルのインデックス情報とSQLのWhere節を分析してみると、ORDDATEカラムで構成されたIDX03_HINT_T3インデックスを活用したIndex Scanを誘導することがより効率的な方法だと判断できます。


この判断に基づき、以下の改善結果を見てみましょう。

改善SQL:


SELECT /*+ INDEX(T3 IDX03_HINT_T3) */ --- 수행방식을 Table Full Scan에서 Index로 변경
       COUNT( * )
FROM   HINT_T3 T3
WHERE  1 = 1
AND    GOODS_NO BETWEEN '1' AND '100'
AND    ORDDATE BETWEEN TO_DATE('2013-01-01','YYYY-MM-DD') AND TO_DATE('2013-01-31','YYYY-MM-DD');

-----------------------------------------------------------------------------------------------
| Id  | Operation                    | Name          | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |               |        |      1 |00:00:00.01 |       4 |
|   1 |  SORT AGGREGATE              |               |      1 |      1 |00:00:00.01 |       4 |
|*  2 |   TABLE ACCESS BY INDEX ROWID| HINT_T3       |      1 |      1 |00:00:00.01 |       4 |
|*  3 |    INDEX RANGE SCAN          | IDX03_HINT_T3 |     31 |     31 |00:00:00.01 |       3 |
-----------------------------------------------------------------------------------------------

既存の /*+ FULL(T3) */ ヒントを ORDDATE 条件で Index Scan を誘導するために /*+ INDEX(T3 IDX03_HINT_T3) */ に変更したら、たった4ブロックだけアクセスするかなり効率的な結果を示しました。

したがって、既存のヒント(/*+ FULL(T3) */)をIndex Scanを誘導するように変更するガイドをして、ヒントを適用させるのは当然の判断と言えます。

ただし、当該SQLが動的Where節の性格を持つSQLであることを知らずに適用した場合、予期せぬ大きな性能問題が発生する可能性があります。

下記の例は当該SQLが別の条件で実行された例で、 /*+ INDEX(T3 IDX03_HINT_T3) */ ヒントがそのまま適用された場合です。

誤って改善されたSQLによる性能低下の場合:


SELECT /*+ INDEX(T3 IDX03_HINT_T3) */
       COUNT( * )
FROM   HINT_T3 T3
WHERE  1 =1 
AND    GOODS_NO BETWEEN '1' AND '100'
AND    CUST_NO BETWEEN '1' AND '100'
AND    ORDDATE >= TO_DATE('2013-01-01','YYYY-MM-DD');

-----------------------------------------------------------------------------------------------
| Id  | Operation                    | Name          | A-Rows |   A-Time   | Buffers | Reads  |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |               |      1 |00:00:13.64 |   17143 |  17139 |
|   1 |  SORT AGGREGATE              |               |      1 |00:00:13.64 |   17143 |  17139 |
|*  2 |   TABLE ACCESS BY INDEX ROWID| HINT_T3       |     50 |00:00:13.64 |   17143 |  17139 |
|*  3 |    INDEX RANGE SCAN          | IDX03_HINT_T3 |   2500K|00:00:06.71 |    6636 |   6633 |
-----------------------------------------------------------------------------------------------

上記の結果はどうでしょうか? 性能向上のために追加したヒントが、逆に性能問題を引き起こす原因となってしまったのがお分かりになると思います。

Where節を見ると、既存のORDDATE条件が1ヶ月に該当するBETWEEN条件から、データ全体に該当する’2013-01-01’より大きい日付に該当する条件に変更されたことが分かります。続いて変更されたWhere節を分析してみると、追加されたCUST_NO条件でIndex Scanを誘導する方がより良い効果が期待できます。しかし、すでに固定されたヒントにより、オプティマイザはORDDATE条件に該当するインデックスを選択せざるを得ず、上記のような結果が出ました。

あえて別の見方をするのであれば、最初のヒント /*+ FULL(T3) */ が可変的な条件状況に関係なく一定の性能を保証する方法として解釈するのも無理がないほどです。

したがって、SQLの性能を改善する前に、そのSQLの業務がどのような性格であるかを把握することが常に高い優先順位にあります。今回のテーマのように動的Where節を持つSQLの場合、常に固定的に入力しなければならない条件があるか、可変的に追加されたり、削除あるいは変更される条件があるかを先に把握しなければなりませんでした。もし、その点を考慮したら、上記のようなミスは避けることができたでしょう。

ヒントを適用する方法が簡単で、それによって改善されたパフォーマンスが得られる場合はよく経験することができます。しかし、ヒントを適用するだけで、すべての状況で絶対的な性能改善を保証すると断言できない理由も多くあります。そのため、データの性質、SQLの性質、業務の性質などを考慮したヒントの適用が必要でしょう。

今回のテーマを通じてヒントの適用方法を習得するのは、結局、DBサーバーの性能を改善するためであることを忘れずに、紹介したヒントの種類と適用方法、そして適用時の注意事項についての十分な理解を基に業務に使用してください。

SQLチューニング 2nd Season(第25回)終

次回のSQLチューニングブログは・・・

SQLチューニングブログ 2nd Season(第4章)
「 Dynamic SQLチューニング方法 」

~ 次回からは新しいテーマでお届けしていきます ~

私たちは 日本のITインフラ における

プロジェクト運営 ~ システム運用 の安定化と効率化を推進します。

日本エクセムのデータベースソリューション

日本エクセムの最新情報は公式SNSでも配信中
画像に alt 属性が指定されていません。ファイル名: 日本エクセム公式Xロゴ.png
画像に alt 属性が指定されていません。ファイル名: 日本エクセム公式Facebookロゴ.png

SQLチューニングブログについてのお問い合わせは

日本エクセム株式会社
日本エクセム株式会社 営業推進部

sales@ex-em.co.jp

PHP Code Snippets Powered By : XYZScripts.com