SQLチューニングを行っていると、Viewに対してヒントを指定したくなることがある。
ある用途のためにViewの定義にヒント句を書いてしまうと、
別の用途でViewを使用した時に良くない実行結果になってしまうことがあるため推奨されない。
ViewへのヒントはTableのときと同じようには記述できないことに注意する。
方法1:グローバルヒントを使う
これは単一表に対するヒントを指定したい場合(INDEXなど1つの表のみ指定するもの)、
最も簡単な方法となる。
複数表ヒント(LEADINGなど2つ以上の表を指定するもの)には使用できない等の制約があるため、
万能ではないことに注意する。
(例)View(V1)があり、View内のTable(T1、T2がある)T1に対して、Index(I1)を指定するヒント
FROM V1
※View内のTableを指定する構文 ⇒ VIEW名.TABLE名
View内のTableに別名が指定されている場合 ⇒ VIEW名.TABLE別名.TABLE名
方法2:問合せブロック(Query Block)付きヒントを使う
これは単一表ヒント、複数表ヒントの両方に使用できる。
問合せブロックとは、View(副問合せ(インラインビュー)もViewと考える)で定義されたSELECT文のことである。
問合せブロックの名前は、以下の2通りで指定する。
・システムが自動的にブロック毎につけたもの
・自分で定義するもの(QB_NAMEヒントを入れる)
通常、Viewに対して自分で定義する問合せブロック名というのは指定できない(Viewの定義の方に書かれているSELECT文にQB_NAMEヒントを入れれば出来るかもしれないが未確認)ため、
実際にSQLを実行(あるいはEXPLAIN PLANを実行)して実行計画を確認する際に、
問合せブロック名も含めて確認するという作業が必要になる。
実行計画を確認する際に、問合せブロック名まで表示させるSQL
1.実際に実行したSQL IDがわかっている場合
(Oracle:実行されているSQLをリアルタイムで監視し、問題のあるSQLの実行計画を確認する
にあるツールやSQLを使って確認できる)
set pagesize 50000
set trimspool on
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('SQL ID名',0,'ALL ALLSTATS LAST'));
※ パラメータは、ALLでなくてALIASでもよい
2.EXPLAIN PLANを実行した直後に確認する場合
set pagesize 50000
set trimspool on
SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY(format=>'ALL ALLSTATS LAST'));
※ formatのパラメータのうち、ALLの部分はALIASでもよい
<実行例>
以下のSQLを実行した際の実行計画確認
--------------------------------------------------------------------
Plan hash value: 3271411982
------------------------------------------------------
| Id | Operation | Name | E-Rows |
------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
| 1 | NESTED LOOPS | | 1 |
| 2 | NESTED LOOPS | | 1 |
| 3 | INDEX FULL SCAN | I1 | 1 |
|* 4 | INDEX RANGE SCAN | I2 | 1 |
| 5 | TABLE ACCESS BY INDEX ROWID| T2 | 1 |
------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$F5BB74E1
3 - SEL$F5BB74E1 / T1@SEL$2
4 - SEL$F5BB74E1 / T2@SEL$2
5 - SEL$F5BB74E1 / T2@SEL$2
※上記の例では、問合せブロック名は「SEL$F5BB74E1」であるが、ヒントとして指定する場合は、黄色文字の部分(Object Aliasの方)を使用する。
この場合、例えば、実行計画内のId=4のでINDEXを使用しているが、このINDEXは、「SEL$2」という問合せブロック内にあるT2のものというように読み取る。
T2テーブルでINDEXを使用しないようにするためNO_INDEXヒントをつけてみる。
ここで先ほど確認した問合せブロック名を使用する。
----------------------------------------------------------------------------
Plan hash value: 2669822726
----------------------------------------------------------------------------
| Id | Operation | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 21 | 2 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 1 | 21 | 2 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL| T2 | 1 | 14 | 2 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | I1 | 1 | 7 | 0 (0)| 00:00:01 |
----------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$F5BB74E1
2 - SEL$F5BB74E1 / T2@SEL$2
3 - SEL$F5BB74E1 / T1@SEL$2
※T2へのアクセスが「TABLE ACCESS FULL」となった。