ヘッダーをスキップ
Oracle® Databaseパフォーマンス・チューニング・ガイド
11gリリース2 (11.2)
B56312-06
  ドキュメント・ライブラリへ移動
ライブラリ
製品リストへ移動
製品
目次へ移動
目次
索引へ移動
索引

前
 
次
 

19 オプティマイザ・ヒントの使用方法

オプティマイザ・ヒントをSQL文で使用して実行計画を変更できます。ヒントを使用して、特定のアプローチの使用をオプティマイザに指示する方法を説明します。

この章には次の項があります。

19.1 オプティマイザ・ヒントの概要

ヒントはオプティマイザに対する指示です。SQLを記述する際に、オプティマイザが認識していないデータに関する情報を、設計者が認識している場合があります。ヒントを使用することで、通常オプティマイザによって行われる決定を行うことができ、コストのかかる計画をオプティマイザに選択させることもできます。

テスト環境または開発環境で、ヒントを使用して特定のアクセス・パスのパフォーマンスをテストできます。たとえば、ある問合せに対しては、特定の索引を選択する方がよい場合もあります。この場合は、ヒントを使用して、オプティマイザが適切な実行計画を使用するように指示できます。

ヒントのデメリットは、管理、チェックおよび制御の必要なコードが追加される点です。データベースやホスト環境の変更によって、ヒントが非推奨になり、負の結果をもたらす場合もあります。このため、ヒントはテストの際に使用しますが、SQL実行計画の管理には、SQLチューニング・アドバイザやSQL計画ベースラインなどの他の方法を使用します。

Oracle Databaseでは60を超えるヒントがサポートされ、各ヒントには0個または1つ以上のパラメータがあります。文ブロックはヒントを含むコメントを1つだけ持つことができ、SELECTUPDATEINSERTMERGEまたはDELETEの各キーワードに続けてコメントを指定します。たとえば、次のヒントは、employees表の最初の10行を最小限のコストで戻す問合せ計画を選択するよう、オプティマイザに指示します。

SELECT /*+ FIRST_ROWS(10) */ * FROM employees;

関連項目:

Oracle Databaseでサポートされるヒントの一覧については、『Oracle Database SQL言語リファレンス』を参照してください。

19.1.1 ヒントの型

ヒントは、次の一般的な型に分類されます。

  • 単一表

    単一表ヒントは、1つの表またはビュー上で指定します。単一表ヒントの例として、INDEXおよびUSE_NLがあります。

  • 複数表

    複数表ヒントは単一表ヒントに似ていますが、ヒントで1つ以上の表またはビューを指定できる点が異なります。複数表ヒントの例には、LEADINGがあります。USE_NL(table1 table2)は、USE_NL(table1)およびUSE_NL(table2)のショートカットであるため、複数表ヒントとはみなされません。

  • 問合せブロック

    問合せブロック・ヒントでは、単一の問合せブロックが処理されます。問合せブロック・ヒントの例として、STAR_TRANSFORMATIONおよびUNNESTがあります。

  • 文ヒントはSQL文全体に適用されます。文ヒントの例には、ALL_ROWSがあります。

19.1.2 カテゴリ別のヒント

オプティマイザ・ヒントは次のカテゴリにグループ分けされます。

このようなカテゴリと各カテゴリ内に含まれるヒントについては、次の各項で説明します。


関連項目:

構文と各ヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

19.1.2.1 最適化アプローチと目標のヒント

ALL_ROWSヒントおよびFIRST_ROWS(n)ヒントでは、最適化アプローチまたは目標のいずれかを選択できます。最適化アプローチと目標を指定するヒントがSQL文に含まれている場合、オプティマイザは、統計の有無、OPTIMIZER_MODE初期化パラメータの値およびALTER SESSION文のOPTIMIZER_MODEパラメータにかかわらず、指定されたアプローチを使用します。


注意:

オプティマイザの目標は直接実行される問合せにのみ適用されます。ヒントを使用して、PL/SQLの内部から実行されるSQL文のためのアクセス・パスを指定してください。ALTER SESSION ... SET OPTIMIZER_MODE文は、PL/SQLの内部から実行されるSQLには作用しません。

SQL文にALL_ROWSヒントまたはFIRST_ROWS(n)ヒントを指定した場合、データ・ディクショナリ内に、文がアクセスする表に関する統計情報が作成されていないと、オプティマイザは、デフォルトの統計値(そのような表に割り当てられている記憶域など)を使用して、欠けている統計を見積ってから、実行計画を選択します。これらの見積りはDBMS_STATSパッケージで収集した値ほど正確でない場合があるため、統計値の収集にはDBMS_STATSを使用します。

ALL_ROWSヒントまたはFIRST_ROWS(n)ヒントとともに、アクセス・パスまたは結合操作のヒントを指定した場合、オプティマイザはヒントによって指定されたアクセス・パスと結合操作を優先します。


関連項目:

マージ可能なビューでのヒントの動作については、「ビューでの最適化アプローチと目標のヒント」を参照してください。

19.1.2.2 オプティマイザ機能を有効化するヒント

OPTIMIZER_FEATURES_ENABLEヒントは、Oracle Databaseのリリース番号に基づいて、一連のオプティマイザ機能を有効化する包括的パラメータとして機能します。このヒントは、データベースのアップグレード後に、計画の回帰をチェックするのに役立ちます。

リリース番号をヒントの引数として指定します。次の例は、Oracle Database 11gリリース1(11.1.0.6)のオプティマイザ機能を使用して問合せを実行します。

SELECT /*+ optimizer_features_enable('11.1.0.6') */ employee_id, last_name
FROM    employees
ORDER BY employee_id;

関連項目:

OPTIMIZER_FEATURES_ENABLE初期化パラメータの詳細は、『Oracle Databaseリファレンス』を参照してください。

19.1.2.3 アクセス・パスに関するヒント

次のヒントは、特定のアクセス・パスを使用して表にアクセスするようオプティマイザに指示します。

  • FULL

  • CLUSTER

  • HASH

  • INDEXおよびNO_INDEX

  • INDEX_ASCおよびINDEX_DESC

  • INDEX_COMBINEおよびINDEX_JOIN

  • INDEX_JOIN

  • INDEX_FFSおよびNO_INDEX_FFS

  • INDEX_SSおよびNO_INDEX_SS

  • INDEX_SS_ASCおよびINDEX_SS_DESC

これらのヒントの1つを指定すると、索引またはクラスタの存在およびSQL文の構文の構成に基づいて、指定したアクセス・パスが使用可能な場合にのみ、指定したアクセス・パスがオプティマイザによって選択されます。ヒントで指定されたアクセス・パスが使用可能でない場合、オプティマイザはその指定を無視します。

アクセスする表は、文に指定する場合と同じように正確に指定してください。文が表の別名を使用している場合、表の名前ではなく、表の別名をヒントで使用する必要があります。スキーマ名が文中にある場合は、ヒント内の表名にそのスキーマ名を入れないでください。


注意:

アクセス・パスのヒントで、SELECT文のFROM句にSAMPLEオプションを指定した場合、Oracle Databaseはヒントを無視します。


関連項目:


19.1.2.4 結合順序のヒント

次のヒントは結合順序を指示します。

  • LEADING

  • ORDERED

19.1.2.5 結合操作のヒント

次のヒントでは、オプティマイザが表の特定の結合操作を使用するように指示します。

  • USE_NLおよびNO_USE_NL

  • USE_NL_WITH_INDEX

  • USE_MERGEおよびNO_USE_MERGE

  • USE_HASHおよびNO_USE_HASH

  • NO_USE_HASH

USE_NLヒントとUSE_MERGEヒントは、結合順序のヒントとともに使用することをお薦めします。「結合順序のヒント」を参照してください。Oracle Databaseでは、参照表を結合の内部表として使用する場合、これらのヒントを使用します。参照表が外部表の場合は、これらのヒントを無視します。

マージ可能なビューでのヒントの動作については、「ビューに対するアクセス・パスと結合のヒント」および「ビュー内のアクセス・パスと結合のヒント」を参照してください。

19.1.2.6 オンライン・アプリケーション・アップグレードのヒント

オンライン・アプリケーション・アップグレードのヒントは、編集ベースの再定義を使用してオンライン・アプリケーション・アップグレードを実行する際にINSERT操作とUPDATE操作の競合を処理する方法を提案します。

  • CHANGE_DUPKEY_ERROR_INDEX

  • IGNORE_ROW_ON_DUPKEY_INDEX

  • RETRY_ON_ROW_CHANGE

CHANGE_DUPKEY_ERROR_INDEXヒントとIGNORE_ROW_ON_DUPKEY_INDEXヒントを使用して、オンライン・アプリケーション・アップグレードの際にINSERT操作の競合を処理できます。CHANGE_DUPKEY_ERROR_INDEXを使用して、指定した列または索引セットの一意キー違反を識別できます。一意キー違反がINSERT操作またはUPDATE操作で検出されると、ORA-001ではなくORA-38911エラーが報告されます。IGNORE_ROW_ON_DUPKEY_INDEXを使用すると、指定した列または索引セットの一意キー違反を無視できます。一意キー違反が単一表のINSERT操作の際に検出された場合、行レベルのロールバックが行われ、実行は次の入力行から再開します。このため、一意キー違反によって、INSERT操作が終了またはエラーが報告されることはありません。

RETRY_ON_ROW_CHANGEヒントを使用して、オンライン・アプリケーション・アップグレードの際にUPDATE操作の競合を処理できます。変更する行セットを決定した時点からその行セットを実際に変更するまでに1つ以上の行が変更された場合、このヒントを使用して、UPDATE操作またはDELETE操作を再試行できます。


関連項目:

編集ベースの再定義を使用したオンライン・アプリケーション・アップグレードの実行の詳細は、『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』を参照してください。

19.1.2.7 パラレル実行のヒント

パラレル実行のヒントは、オプティマイザが操作を並列化するかどうか、および並列化の方法を指示します。次のパラレル・ヒントを使用できます。

  • PARALLELおよびNO_PARALLEL

  • PARALLEL_INDEXおよびNO_PARALLEL_INDEX

  • PQ_DISTRIBUTE

次の項では、ヒントを機能別のカテゴリに分類しています。


関連項目:

  • パラレル実行の使用方法の詳細は、『Oracle Database VLDBおよびパーティショニング・ガイド』を参照してください。

  • パラレル実行の詳細は、『Oracle Database 2日でデータ・ウェアハウス・ガイド』を参照してください。


19.1.2.7.1 並列度を制御するヒント

PARALLELキーワードで始まるヒントは、問合せの並列度を示します。NO_PARALLELで始まるヒントは、並列性を無効にします。


注意:

/*+ NOAPPEND PARALLEL */ヒントを使用すると、従来の挿入をパラレル・モードで実行できます。

並列度は、文またはオブジェクト・レベルで指定できます。ヒントにオブジェクトが明示的に指定されていない場合、並列性は文レベルで起こります。ほとんどのヒントとは対照的に、文レベルのパラレル・ヒントは、オブジェクト・レベルのヒントよりも優先されます。

オブジェクト・レベルと文レベルの並列設定の違いを理解するには、たとえば、次の手順を実行します。

  1. employees表の並列度を2に設定し、departments表の並列度を無効にします。次に例を示します。

    ALTER TABLE employees PARALLEL 2;
    ALTER TABLE departments NOPARALLEL;
    
  2. 次のようなSELECT文を実行します。

    SELECT /*+ PARALLEL(employees 3) */ e.last_name, d.department_name
    FROM   employees e, departments d
    WHERE  e.department_id=d.department_id;
    

    employeesPARALLELヒントは、手順1で指定したこの表の並列度2を上書きします。

    例19-1の実行計画で、IN-OUT列のPCWPemployeesのパラレル・アクセスを示し、Sdepartmentsのシリアル・アクセスを示しています。departmentsへのアクセスは、手順1でこの表にNOPARALLELを適用しているため、シリアル化されています。

    例19-1 /*+ PARALLEL(employees 3) */ヒントが指定された問合せの実行計画

    ----------------------------------------------------------------------------------------------------------------
    | Id | Operation               | Name        | Rows | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib 
    ----------------------------------------------------------------------------------------------------------------
    |  0 | SELECT STATEMENT        |             |   14 |   588 |     5  (20)| 00:00:01 |        |      |          |
    |  1 |  PX COORDINATOR         |             |      |       |            |          |        |      |          |
    |  2 |   PX SEND QC (RANDOM)   | :TQ10001    |   14 |   588 |     5  (20)| 00:00:01 |  Q1,01 | P->S | QC (RAND)|
    |* 3 |    HASH JOIN            |             |   14 |   588 |     5  (20)| 00:00:01 |  Q1,01 | PCWP |          |
    |  4 |     BUFFER SORT         |             |      |       |            |          |  Q1,01 | PCWC |          |
    |  5 |      PX RECEIVE         |             |    4 |    88 |     2   (0)| 00:00:01 |  Q1,01 | PCWP |          |
    |  6 |       PX SEND BROADCAST | :TQ10000    |    4 |    88 |     2   (0)| 00:00:01 |        | S->P | BROADCAST|
    |  7 |        TABLE ACCESS FULL| DEPARTMENTS |    4 |    88 |     2   (0)| 00:00:01 |        |      |          |
    |  8 |     PX BLOCK ITERATOR   |             |   14 |   280 |     2   (0)| 00:00:01 |  Q1,01 | PCWC |          |
    |  9 |      TABLE ACCESS FULL  | EMPLOYEES   |   14 |   280 |     2   (0)| 00:00:01 |  Q1,01 | PCWP |          |
    ----------------------------------------------------------------------------------------------------------------
    
  3. 次のようなSELECT文を実行します。

    SELECT /*+ PARALLEL(4) */ hr_emp.last_name, d.department_name
    FROM   employees hr_emp, departments d
    WHERE  hr_emp.department_id=d.department_id;
    

    PARALLELヒントにスキーマ・オブジェクトが指定されていないため、ヒントの有効範囲はオブジェクトではなく文です。この文では、employees表およびdepartments表の問合せが並列度4で実行され、各表に定義された並列設定は上書きされます。

19.1.2.7.2 結合の分散方法を制御するヒント

PQ_DISTRIBUTEヒントは、指定した結合操作の分散方法を制御します。基本構文は次のとおりです。このdistributionは、結合の左側と右側にプロデューサ・スレーブとコンシューマ・スレーブを使用して分散させる方法です。

/*+ PQ_DISTRIBUTE(tablespec, distribution) */

たとえば、HASH,HASH分散では、結合キーにハッシュ関数を使用して、各表の行はコンシューマ問合せサーバーにマップされます。マッピングが完了すると、各問合せサーバーは、結果として生成されるパーティション・ペアで結合を実行します。この分散は、表のサイズがほぼ等しく、結合操作をハッシュ結合またはソート/マージ結合で行う場合にお薦めします。次の問合せのヒントでは、ハッシュ分散を使用しています。

SELECT /*+ORDERED PQ_DISTRIBUTE(departments HASH, HASH) USE_HASH (departments)*/
       e.employee_id, d.department_name
FROM   employees e, departments d
WHERE  e.department_id=d.department_id;

関連項目:

PQ_DISTRIBUTEヒントの有効な構文とセマンティクスの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

19.1.2.7.3 ロードの分散方法を制御するヒント

PQ_DISTRIBUTEヒントは、パラレルINSERT ... SELECT文とパラレルCREATE TABLE AS SELECT文に適用されて、プロデューサ(問合せ)スレーブとコンシューマ(ロード)スレーブ間での行の分散方法を指定します。

たとえば、PARTITION分散は、ロードする表のパーティション情報を使用して、問合せスレーブからロード・スレーブに行を分散します。この方法は、次の条件を満たす場合に使用します。

  • 問合せとロードの操作をそれぞれスレーブとして統合することが不可能である(または望ましくない)場合。

  • ロードするパーティションの数がロード・スレーブの数に等しいかそれ以上の場合。

  • 入力データがロードするパーティション間に均等に分布している場合。

次のサンプル文は、表を作成し、PARTITION分散方法を指定しています。

CREATE /*+ PQ_DISTRIBUTE(lineitem, PARTITION) */ TABLE lineitem
  NOLOGGING PARALLEL 16
  PARTITION BY HASH (l_orderkey) PARTITIONS 512
  AS SELECT * FROM lineitemxt; 

一方、NONE分散は、問合せとロードの操作をそれぞれスレーブとして統合します。このため、すべてのスレーブがすべてのパーティションをロードします。偏りがない場合、この分散を使用すると、行の分散によるオーバーヘッドを回避できます。次のサンプルSQL文では、lineitem表へのINSERTにNONE分散を指定しています。

INSERT /*+ APPEND PARALLEL(LINEITEM, 16) PQ_DISTRIBUTE(LINEITEM, NONE) */
  INTO lineitem
  (SELECT * FROM lineitemxt);

19.1.2.8 問合せの変換に関するヒント

次の各ヒントは、特定のSQL問合せ変換を使用するようオプティマイザに指示します。

  • NO_QUERY_TRANSFORMATION

  • USE_CONCAT

  • NO_EXPAND

  • REWRITEおよびNO_REWRITE

  • MERGEおよびNO_MERGE

  • STAR_TRANSFORMATIONおよびNO_STAR_TRANSFORMATION

  • FACTおよびNO_FACT

  • UNNESTおよびNO_UNNEST

19.1.2.9 その他のヒント

この項ではその他のいくつかのヒントを説明します。

  • APPENDAPPEND_VALUESおよびNOAPPEND

  • CACHEおよびNOCACHE

  • PUSH_PREDおよびNO_PUSH_PRED

  • PUSH_SUBQおよびNO_PUSH_SUBQ

  • QB_NAME

  • CURSOR_SHARING_EXACT

  • DRIVING_SITE

  • DYNAMIC_SAMPLING

  • MODEL_MIN_ANALYSIS

19.2 ヒントの指定方法

ヒントは、それらが含まれるSQL文ブロックの最適化のみに適用されます。文ブロックは、次のいずれかの文または文の一部です。

  • 単純なSELECT文、UPDATE文またはDELETE

  • 複合文の親文または副問合せ

  • 複合問合せの一部

たとえば、UNION演算子で結合した2つの構成要素の問合せから成る複合問合せには、各構成要素の問合せに対して1つずつ、合計2つのブロックがあります。このため、この最初の構成要素の問合せにおけるヒントはその最適化のみに適用され、2番目の構成要素の問合せの最適化には適用されません。

次の各項では、ヒントの使用方法をさらに詳しく説明します。

19.2.1 ヒント全セットの指定方法

ヒントを使用するとき、最適な実行計画を確保するために、ヒントの完全なセットを指定することが必要な場合があります。たとえば、多数の表の結合を含む非常に複雑な問合せで、特定の表にのみINDEXヒントを指定した場合、オプティマイザは、使用するその他のアクセス・パスおよび対応する結合方法を決定する必要があります。したがって、INDEXヒントを指定しても、オプティマイザが選択する結合方法およびアクセス・パスによっては、要求した索引を使用できない場合もあるため、オプティマイザの判断により、そのヒントは使用されない場合もあります。

例19-2では、LEADINGヒントにより正確な結合順序が指定されています。また、結合方法も指定されています。

例19-2 ヒント全セットの指定方法

SELECT /*+ LEADING(e2 e1) USE_NL(e1) INDEX(e1 emp_emp_id_pk) 
           USE_MERGE(j) FULL(j) */
    e1.first_name, e1.last_name, j.job_id, sum(e2.salary) total_sal
  FROM employees e1, employees e2, job_history j
  WHERE e1.employee_id = e2.manager_id
    AND e1.employee_id = j.employee_id
    AND e1.hire_date = j.start_date
  GROUP BY e1.first_name, e1.last_name, j.job_id
  ORDER BY total_sal;

19.2.2 ヒントにおける問合せブロックの指定方法

問合せにおける問合せブロックを識別するために、ヒントでオプションの問合せブロック名を使用して、ヒントが適用される問合せブロックを指定できます。問合せブロック引数の構文の形式は@queryblockです。queryblockは、問合せ内のブロックを指定する識別子です。queryblock識別子は、システム生成またはユーザー指定のいずれかとなります。

次のガイドラインに留意してください。

  • 問合せでEXPLAIN PLANを使用すると、システム生成の識別子を取得できます。NO_QUERY_TRANSFORMATIONヒントを使用して問合せのEXPLAIN PLANを実行することで、変換前の問合せブロック名を調べることができます。

  • QB_NAMEヒントを使用して、ユーザー指定の名前を設定できます。

前提事項

このチュートリアルでは、次のことが前提となっています。

  • ネストされた問合せブロックが含まれるemployeesjob_historyの結合ビューを作成します。

  • ビューのすべての行を問い合せますが、NO_UNNESTヒントは問合せブロックにのみ適用します。

NO_UNNESTヒントを問合せブロックに適用するには、次の手順を実行します。 

  1. SQL*Plusを起動し、ユーザーhrとしてログインします。

  2. ビューを作成します。

    たとえば、次の文を実行します。

    CREATE OR REPLACE VIEW v_emp_job_history AS
      SELECT e1.first_name, e1.last_name, j.job_id, sum(e2.salary) total_sal
      FROM   employees e1, (SELECT * FROM employees e3) e2, job_history j
      WHERE  e1.employee_id = e2.manager_id
      AND    e1.employee_id = j.employee_id
      AND    e1.hire_date = j.start_date
      AND    e1.salary = ( SELECT max(e2.salary) 
                           FROM employees e2 
                           WHERE e2.department_id = e1.department_id ) 
      GROUP BY e1.first_name, e1.last_name, j.job_id
      ORDER BY total_sal;
    
  3. v_emp_job_historyの問合せについてEXPLAIN PLANを実行します。

    たとえば、次のSQL文を実行します。

    EXPLAIN PLAN FOR SELECT * FROM v_emp_job_history; 
    
  4. PLAN TABLEを問い合せます。

    たとえば、次のSQL文を実行します。

    SELECT PLAN_TABLE_OUTPUT 
    FROM   TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ALL'));
    

    計画が表示されます。

  5. 問合せ計画出力で、問合せブロックに関連付けられた操作IDを取得した後、そのIDを使用して問合せブロック名を見つけます。

    たとえば、次の計画は、employees表の全体スキャンが操作11で発生し、この操作が問合せブロック@SEL$4に対応していることを示しています。

    ------------------------------------------------------------------------------
    |Id| Operation                        |Name        |Rows|Bytes|Cost |Time
    ------------------------------------------------------------------------------
    |0 | SELECT STATEMENT                 |            |1   |46   |9(34)|00:00:01|
    .
    .
    .
    |11|          TABLE ACCESS FULL       | EMPLOYEES  |107 |749  |3(0) |00:00:01|
    .
    .
    .
    -------------------------------------------------------------------------------
    
    Query Block Name / Object Alias (identified by operation id):
    -------------------------------------------------------------
     
       1 - SEL$2980E977 / V_EMP_JOB_HISTORY@SEL$1
       2 - SEL$2980E977
       8 - SEL$8F9407EC / VW_SQ_1@SEL$32F848CB
       9 - SEL$8F9407EC
      11 - SEL$8F9407EC / E2@SEL$4
    
  6. NO_UNNESTヒントを使用してビューを問い合せます。

    たとえば、NO_UNNESTヒントを問合せブロック@SEL$4(サンプル出力を参照)に適用するには、次のSQL文を実行します。

    SQL> SELECT /*+ NO_UNNEST( @SEL$4 ) */ * FROM v_emp_job_history;
    
    FIRST_NAME           LAST_NAME                 JOB_ID      TOTAL_SAL
    -------------------- ------------------------- ---------- ----------
    Michael              Hartstein                 MK_REP           6000
    

19.2.3 グローバル表のヒントの指定方法

表を指定するヒントは、一般に、ヒントが呼び出される場所であるDELETESELECTまたはUPDATE問合せブロック内の表を参照します。文によって参照されるビュー内の表は参照しません。ビュー内に表示される表のヒントを指定する場合は、ビューに埋め込まれているヒントではなくグローバル・ヒントを使用することをお薦めします。この章で説明する表ヒントは、ビュー名と表名を含む拡張tablespec構文を使用して、グローバル・ヒントに変換できます。

また、tablespec構文の前にオプションの問合せブロック名を使用できます。「ヒントにおける問合せブロックの指定方法」を参照してください。

表を指定するヒントには、次の構文を使用します。viewはビュー名を指定し、tableは表の名前または別名を指定します。

tablespec::= tablespec.gifの説明が続きます。
図tablespec.gifの説明

ビューのパスが指定されている場合、ヒントは左側から順に解決されます。この場合、1つ目のビューはFROM句に含まれる必要があり、それ以降の各ビューは、前のビューのFROM句で指定されている必要があります。


注意:

オプティマイザが解析中に追加のビューを生成するため、ANSI結合構文を使用した問合せには、グローバル・ヒントに対するview_name.table_name表記は使用できません。ANSI結合構文を使用する場合には、view_name.table_name表記のかわりにヒントに問合せブロック名を指定してください。

たとえば、例19-3では、ビューvを作成して、部門内で給与が最高である各従業員について、従業員の姓名、従業員の最初のジョブおよび従業員の直属の部下全員の合計給与を戻します。データを問い合せる場合、ビューe2の表e3に索引emp_job_ixを使用することを強制できます。

例19-3 グローバル・ヒントの使用例

CREATE OR REPLACE VIEW v AS
  SELECT e1.first_name, e1.last_name, j.job_id, sum(e2.salary) total_sal
  FROM   employees e1, ( SELECT * FROM employees e3) e2, job_history j
  WHERE e1.employee_id = e2.manager_id
  AND e1.employee_id = j.employee_id
  AND e1.hire_date = j.start_date
  AND e1.salary = ( SELECT max(e2.salary) FROM employees e2
                    WHERE e2.department_id = e1.department_id )
  GROUP BY e1.first_name, e1.last_name, j.job_id
  ORDER BY total_sal;

グローバル・ヒント構造を使用することで、ビューe2の本体に索引ヒントを指定して、ビューvの変更を防ぐことができます。表e3の索引emp_job_ixを使用するよう強制するには、次のいずれかの文を使用します。

SELECT /*+ INDEX(v.e2.e3 emp_job_ix) */  * FROM v;

SELECT /*+ INDEX(@SEL$2 e2.e3 emp_job_ix) */ * FROM v;

SELECT /*+ INDEX(@SEL$3 e3 emp_job_ix) */ * FROM v;

注意:

Oracle Databaseでは、複数の問合せブロックを参照するグローバル・ヒントを無視します。たとえば、次の問合せのLEADINGヒントでは、表aおよびビュー問合せブロックvを含むメイン問合せブロックにドット表記を使用しているため、このヒントは無視されます。
SELECT /*+ LEADING(v.b a v.c) */ *
FROM a, v
WHERE a.id = v.id;

この問題を回避するため、ヒントでの問合せブロックの指定には@SEL表記を使用することをお薦めします。

SELECT /*+ LEADING(A@SEL$1 B@SEL$2 C@SEL$2) */
FROM a a, v v
WHERE a.id = v.id;

例19-4 NO_MERGEを含むグローバル・ヒントの使用方法

例19-4に示すように、グローバル・ヒント構文は、マージ不可のビューにも適用されます。

CREATE OR REPLACE VIEW v1 AS
  SELECT *
    FROM employees
    WHERE employee_id < 150;

CREATE OR REPLACE VIEW v2 AS
  SELECT v1.employee_id employee_id, departments.department_id department_id
    FROM v1, departments
    WHERE v1.department_id = departments.department_id;

SELECT /*+ NO_MERGE(v2) INDEX(v2.v1.employees emp_emp_id_pk)
                        FULL(v2.departments) */ *
  FROM v2
  WHERE department_id = 30;

このヒントは、v2をマージ不可能にし、従業員および部門表のアクセス・パス・ヒントを指定します。これらのヒントは、マージされていないビューv2にプッシュされます。

19.2.4 複合索引ヒントの指定方法

索引を指定するヒントには、次のように、単純な索引名またはカッコで括られた列のリストのいずれかを使用できます。

indexspec::=

indexspec.gifの説明が続きます。
図indexspec.gifの説明

セマンティクスは、次のとおりです。

  • tableは表の名前を指定します。

  • columnは、指定された表内の列名を指定します。

    • オプションで列の前に表修飾子を付けることができるため、ヒントにより、索引列が索引付きの表とは別の表にあるビットマップ結合索引を指定できます。問合せに表修飾子がある場合は、別名ではなく、実表である必要があります。

    • 索引指定の各列は、式ではなく、指定された表のベース列である必要があります。索引指定で指定された列がファンクション索引の接頭辞を形成している場合を除き、列指定を使用してファンクション索引をヒントで指定することはできません。

  • indexは、索引名を指定します。

    ヒントの指定でtablespecの次にindexspecが続く場合、表名と索引名を区切るカンマを挿入できますが、必須ではありません。複数のindexspecを区切るカンマも挿入できますが、必須ではありません。

ヒントは次のように解決されます。

  • 索引名が指定されている場合は、指定された索引のみが考慮されます。

  • 列リストが指定されており、指定された列と数および順序が一致する列を持つ索引が存在する場合は、その索引のみが考慮されます。このような索引が存在しない場合、指定された列が接頭辞として指定順序どおりに含まれる、表に対する索引が考慮されます。いずれの場合も、一致するすべての索引に対してユーザーが個別に同じヒントを指定した場合と同じ動作になります。

たとえば、例19-3job_history表には、employee_id列に対する単一列索引と、employee_idおよびstart_date列に対する連結索引があります。特定の索引を使用するようオプティマイザに指示するには、問合せに次のようなヒントを指定します。

SELECT /*+ INDEX(v.j jhist_employee_ix (employee_id start_date)) */ * FROM v;

19.3 ビューでのヒントの使用方法

あるコンテキストで定義されたビューが、別のコンテキストで使用される可能性があるため、ビュー内、またはビュー(副問合せ)に対するヒントはお薦めできません。また、このようなヒントによって予想外の実行計画が発生する可能性があります。特に、ビュー内のヒントまたはビューに対するヒントは、そのビューがトップレベルの問合せにマージ可能かどうかによって処理方法が異なります。

ビューまたは副問合せで表のヒントを指定するには、グローバル・ヒント構文をお薦めします。「グローバル表のヒントの指定方法」を参照してください。

次の項では、ビューでヒントを使用する場合の動作について説明します。

19.3.1 ヒントおよび複合ビュー

デフォルトでは、複合ビューでヒントは使用できません。たとえば、複合ビューに対する選択を行う問合せでヒントを指定しても、ビュー内にヒントがプッシュされないため、そのヒントは適用されません。


注意:

ビューが単一表の場合、ヒントは伝播されません。

ヒントは、ベース・ビュー内に存在する場合を除き、ビューに対する問合せからは適用されません。

19.3.2 ヒントとマージ可能ビュー

マージ可能なビューは、ビューを定義する問合せで置換できるビューのことです。たとえば、次のようにビューを作成します。

CREATE OR REPLACE VIEW emp_view AS 
  SELECT last_name, department_name FROM employees e, departments d
  WHERE e.department_id=d.department_id;

このビューがマージ可能なのは、次のように、ビュー自体を使用するのではなく、ビューを定義するSELECT文を使用して問合せを最適化できるからです。

SELECT * FROM emp_view;

19.3.2.1 ビューでの最適化アプローチと目標のヒント

最適化アプローチと目標のヒントは、トップレベルの問合せまたはビュー内で起こります。

  • このようなヒントがトップレベルの問合せに存在する場合、ビュー内のヒントの有無にかかわらず、このヒントを使用します。

  • トップレベルのオプティマイザ・モード・ヒントがない場合、参照されるビューですべてのモード・ヒントに一貫性がある場合、それらのモード・ヒントを使用します。

  • 参照されるビューで複数のモード・ヒントが競合する場合、ビューのモード・ヒントをすべて廃棄し、デフォルトまたはユーザー指定のセッション・モードを使用します。

19.3.2.2 ビューに対するアクセス・パスと結合のヒント

参照されるビューに対するアクセス・パス・ヒントと結合ヒントは、そのビューが単一の表を含んでいる場合または単一の表を持つその他のヒント・ビューを参照している場合以外は、無視されます。このような単一表ビューの場合、ビューに対するアクセス・パス・ヒントまたは結合ヒントは、ビュー内の表に対して適用されます。

19.3.2.3 ビュー内のアクセス・パスと結合のヒント

アクセス・パス・ヒントと結合ヒントは、ビュー定義に含めることができます。

  • ビューがインライン・ビューである場合(つまり、ビューがSELECT文のFROM句にある場合)、ビューをトップレベルの問合せとマージするとき、ビュー内のすべてのアクセス・パス・ヒントと結合ヒントが保持されます。

  • インライン・ビュー以外のビューでは、参照問合せが他の表またはビューを参照していない場合(つまり、SELECT文のFROM句にそのビューしか含まれていない場合)のみ、ビュー内のアクセス・パス・ヒントおよび結合ヒントが保持されます。

19.3.3 ヒントおよびマージ不可能なビュー

マージ不可能なビューでは、ビュー内の最適化アプローチおよび目標のヒントは無視されます。つまり、トップレベルの問合せにより最適化モードが決定されます。

マージ不可能なビューはトップレベルの問合せとは別々に最適化されるため、ビュー内のアクセス・パスおよび結合のヒントは保持されます。同じ理由から、トップレベルの問合せ内のビューに対するアクセス・パス・ヒントは無視されます。

ただし、この場合、マージ不可能なビューは表に類似しているため、トップレベルの問合せ内のビューに対する結合ヒントは保持されます。