オプティマイザ・ヒントをSQL文で使用して実行計画を変更できます。ヒントを使用して、特定のアプローチの使用をオプティマイザに指示する方法を説明します。
この章には次の項があります。
ヒントはオプティマイザに対する指示です。SQLを記述する際に、オプティマイザが認識していないデータに関する情報を、設計者が認識している場合があります。ヒントを使用することで、通常オプティマイザによって行われる決定を行うことができ、コストのかかる計画をオプティマイザに選択させることもできます。
テスト環境または開発環境で、ヒントを使用して特定のアクセス・パスのパフォーマンスをテストできます。たとえば、ある問合せに対しては、特定の索引を選択する方がよい場合もあります。この場合は、ヒントを使用して、オプティマイザが適切な実行計画を使用するように指示できます。
ヒントのデメリットは、管理、チェックおよび制御の必要なコードが追加される点です。データベースやホスト環境の変更によって、ヒントが非推奨になり、負の結果をもたらす場合もあります。このため、ヒントはテストの際に使用しますが、SQL実行計画の管理には、SQLチューニング・アドバイザやSQL計画ベースラインなどの他の方法を使用します。
Oracle Databaseでは60を超えるヒントがサポートされ、各ヒントには0個または1つ以上のパラメータがあります。文ブロックはヒントを含むコメントを1つだけ持つことができ、SELECT
、UPDATE
、INSERT
、MERGE
またはDELETE
の各キーワードに続けてコメントを指定します。たとえば、次のヒントは、employees
表の最初の10行を最小限のコストで戻す問合せ計画を選択するよう、オプティマイザに指示します。
SELECT /*+ FIRST_ROWS(10) */ * FROM employees;
関連項目: Oracle Databaseでサポートされるヒントの一覧については、『Oracle Database SQL言語リファレンス』を参照してください。 |
ヒントは、次の一般的な型に分類されます。
単一表
単一表ヒントは、1つの表またはビュー上で指定します。単一表ヒントの例として、INDEX
およびUSE_NL
があります。
複数表
複数表ヒントは単一表ヒントに似ていますが、ヒントで1つ以上の表またはビューを指定できる点が異なります。複数表ヒントの例には、LEADING
があります。USE_NL(table1 table2)
は、USE_NL(table1)
およびUSE_NL(table2)
のショートカットであるため、複数表ヒントとはみなされません。
問合せブロック
問合せブロック・ヒントでは、単一の問合せブロックが処理されます。問合せブロック・ヒントの例として、STAR_TRANSFORMATION
およびUNNEST
があります。
文
文ヒントはSQL文全体に適用されます。文ヒントの例には、ALL_ROWS
があります。
オプティマイザ・ヒントは次のカテゴリにグループ分けされます。
このようなカテゴリと各カテゴリ内に含まれるヒントについては、次の各項で説明します。
関連項目: 構文と各ヒントの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。 |
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
)ヒントとともに、アクセス・パスまたは結合操作のヒントを指定した場合、オプティマイザはヒントによって指定されたアクセス・パスと結合操作を優先します。
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リファレンス』を参照してください。 |
次のヒントは、特定のアクセス・パスを使用して表にアクセスするようオプティマイザに指示します。
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はヒントを無視します。 |
関連項目:
|
次のヒントは結合順序を指示します。
LEADING
ORDERED
次のヒントでは、オプティマイザが表の特定の結合操作を使用するように指示します。
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では、参照表を結合の内部表として使用する場合、これらのヒントを使用します。参照表が外部表の場合は、これらのヒントを無視します。
マージ可能なビューでのヒントの動作については、「ビューに対するアクセス・パスと結合のヒント」および「ビュー内のアクセス・パスと結合のヒント」を参照してください。
オンライン・アプリケーション・アップグレードのヒントは、編集ベースの再定義を使用してオンライン・アプリケーション・アップグレードを実行する際に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アドバンスト・アプリケーション開発者ガイド』を参照してください。 |
パラレル実行のヒントは、オプティマイザが操作を並列化するかどうか、および並列化の方法を指示します。次のパラレル・ヒントを使用できます。
PARALLEL
およびNO_PARALLEL
PARALLEL_INDEX
およびNO_PARALLEL_INDEX
PQ_DISTRIBUTE
次の項では、ヒントを機能別のカテゴリに分類しています。
関連項目:
|
PARALLEL
キーワードで始まるヒントは、問合せの並列度を示します。NO_PARALLEL
で始まるヒントは、並列性を無効にします。
注意: /*+ NOAPPEND PARALLEL */ ヒントを使用すると、従来の挿入をパラレル・モードで実行できます。 |
並列度は、文またはオブジェクト・レベルで指定できます。ヒントにオブジェクトが明示的に指定されていない場合、並列性は文レベルで起こります。ほとんどのヒントとは対照的に、文レベルのパラレル・ヒントは、オブジェクト・レベルのヒントよりも優先されます。
オブジェクト・レベルと文レベルの並列設定の違いを理解するには、たとえば、次の手順を実行します。
employees
表の並列度を2
に設定し、departments
表の並列度を無効にします。次に例を示します。
ALTER TABLE employees PARALLEL 2; ALTER TABLE departments NOPARALLEL;
次のようなSELECT
文を実行します。
SELECT /*+ PARALLEL(employees 3) */ e.last_name, d.department_name FROM employees e, departments d WHERE e.department_id=d.department_id;
employees
のPARALLEL
ヒントは、手順1で指定したこの表の並列度2
を上書きします。
例19-1の実行計画で、IN-OUT
列のPCWP
はemployees
のパラレル・アクセスを示し、S
はdepartments
のシリアル・アクセスを示しています。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 | | ----------------------------------------------------------------------------------------------------------------
次のような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
で実行され、各表に定義された並列設定は上書きされます。
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言語リファレンス』を参照してください。 |
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);
次の各ヒントは、特定の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
この項ではその他のいくつかのヒントを説明します。
APPEND
、APPEND_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
ヒントは、それらが含まれるSQL文ブロックの最適化のみに適用されます。文ブロックは、次のいずれかの文または文の一部です。
単純なSELECT
文、UPDATE
文またはDELETE
文
複合文の親文または副問合せ
複合問合せの一部
たとえば、UNION
演算子で結合した2つの構成要素の問合せから成る複合問合せには、各構成要素の問合せに対して1つずつ、合計2つのブロックがあります。このため、この最初の構成要素の問合せにおけるヒントはその最適化のみに適用され、2番目の構成要素の問合せの最適化には適用されません。
次の各項では、ヒントの使用方法をさらに詳しく説明します。
ヒントを使用するとき、最適な実行計画を確保するために、ヒントの完全なセットを指定することが必要な場合があります。たとえば、多数の表の結合を含む非常に複雑な問合せで、特定の表にのみ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;
問合せにおける問合せブロックを識別するために、ヒントでオプションの問合せブロック名を使用して、ヒントが適用される問合せブロックを指定できます。問合せブロック引数の構文の形式は@
queryblock
です。queryblock
は、問合せ内のブロックを指定する識別子です。queryblock
識別子は、システム生成またはユーザー指定のいずれかとなります。
次のガイドラインに留意してください。
問合せでEXPLAIN
PLAN
を使用すると、システム生成の識別子を取得できます。NO_QUERY_TRANSFORMATION
ヒントを使用して問合せのEXPLAIN
PLAN
を実行することで、変換前の問合せブロック名を調べることができます。
QB_NAME
ヒントを使用して、ユーザー指定の名前を設定できます。
前提事項
このチュートリアルでは、次のことが前提となっています。
ネストされた問合せブロックが含まれるemployees
とjob_history
の結合ビューを作成します。
ビューのすべての行を問い合せますが、NO_UNNEST
ヒントは問合せブロックにのみ適用します。
NO_UNNESTヒントを問合せブロックに適用するには、次の手順を実行します。
SQL*Plusを起動し、ユーザーhr
としてログインします。
ビューを作成します。
たとえば、次の文を実行します。
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;
v_emp_job_history
の問合せについてEXPLAIN PLANを実行します。
たとえば、次のSQL文を実行します。
EXPLAIN PLAN FOR SELECT * FROM v_emp_job_history;
PLAN TABLEを問い合せます。
たとえば、次のSQL文を実行します。
SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ALL'));
計画が表示されます。
問合せ計画出力で、問合せブロックに関連付けられた操作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
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
表を指定するヒントは、一般に、ヒントが呼び出される場所であるDELETE
、SELECT
またはUPDATE
問合せブロック内の表を参照します。文によって参照されるビュー内の表は参照しません。ビュー内に表示される表のヒントを指定する場合は、ビューに埋め込まれているヒントではなくグローバル・ヒントを使用することをお薦めします。この章で説明する表ヒントは、ビュー名と表名を含む拡張tablespec
構文を使用して、グローバル・ヒントに変換できます。
また、tablespec
構文の前にオプションの問合せブロック名を使用できます。「ヒントにおける問合せブロックの指定方法」を参照してください。
表を指定するヒントには、次の構文を使用します。view
はビュー名を指定し、table
は表の名前または別名を指定します。
tablespec::=
図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; この問題を回避するため、ヒントでの問合せブロックの指定には 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
にプッシュされます。
索引を指定するヒントには、次のように、単純な索引名またはカッコで括られた列のリストのいずれかを使用できます。
indexspec::=
セマンティクスは、次のとおりです。
table
は表の名前を指定します。
column
は、指定された表内の列名を指定します。
オプションで列の前に表修飾子を付けることができるため、ヒントにより、索引列が索引付きの表とは別の表にあるビットマップ結合索引を指定できます。問合せに表修飾子がある場合は、別名ではなく、実表である必要があります。
索引指定の各列は、式ではなく、指定された表のベース列である必要があります。索引指定で指定された列がファンクション索引の接頭辞を形成している場合を除き、列指定を使用してファンクション索引をヒントで指定することはできません。
index
は、索引名を指定します。
ヒントの指定でtablespec
の次にindexspec
が続く場合、表名と索引名を区切るカンマを挿入できますが、必須ではありません。複数のindexspec
を区切るカンマも挿入できますが、必須ではありません。
ヒントは次のように解決されます。
索引名が指定されている場合は、指定された索引のみが考慮されます。
列リストが指定されており、指定された列と数および順序が一致する列を持つ索引が存在する場合は、その索引のみが考慮されます。このような索引が存在しない場合、指定された列が接頭辞として指定順序どおりに含まれる、表に対する索引が考慮されます。いずれの場合も、一致するすべての索引に対してユーザーが個別に同じヒントを指定した場合と同じ動作になります。
たとえば、例19-3のjob_history
表には、employee_id
列に対する単一列索引と、employee_id
およびstart_date
列に対する連結索引があります。特定の索引を使用するようオプティマイザに指示するには、問合せに次のようなヒントを指定します。
SELECT /*+ INDEX(v.j jhist_employee_ix (employee_id start_date)) */ * FROM v;
あるコンテキストで定義されたビューが、別のコンテキストで使用される可能性があるため、ビュー内、またはビュー(副問合せ)に対するヒントはお薦めできません。また、このようなヒントによって予想外の実行計画が発生する可能性があります。特に、ビュー内のヒントまたはビューに対するヒントは、そのビューがトップレベルの問合せにマージ可能かどうかによって処理方法が異なります。
ビューまたは副問合せで表のヒントを指定するには、グローバル・ヒント構文をお薦めします。「グローバル表のヒントの指定方法」を参照してください。
次の項では、ビューでヒントを使用する場合の動作について説明します。
デフォルトでは、複合ビューでヒントは使用できません。たとえば、複合ビューに対する選択を行う問合せでヒントを指定しても、ビュー内にヒントがプッシュされないため、そのヒントは適用されません。
注意: ビューが単一表の場合、ヒントは伝播されません。 |
ヒントは、ベース・ビュー内に存在する場合を除き、ビューに対する問合せからは適用されません。
マージ可能なビューは、ビューを定義する問合せで置換できるビューのことです。たとえば、次のようにビューを作成します。
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;
最適化アプローチと目標のヒントは、トップレベルの問合せまたはビュー内で起こります。
このようなヒントがトップレベルの問合せに存在する場合、ビュー内のヒントの有無にかかわらず、このヒントを使用します。
トップレベルのオプティマイザ・モード・ヒントがない場合、参照されるビューですべてのモード・ヒントに一貫性がある場合、それらのモード・ヒントを使用します。
参照されるビューで複数のモード・ヒントが競合する場合、ビューのモード・ヒントをすべて廃棄し、デフォルトまたはユーザー指定のセッション・モードを使用します。
参照されるビューに対するアクセス・パス・ヒントと結合ヒントは、そのビューが単一の表を含んでいる場合または単一の表を持つその他のヒント・ビューを参照している場合以外は、無視されます。このような単一表ビューの場合、ビューに対するアクセス・パス・ヒントまたは結合ヒントは、ビュー内の表に対して適用されます。
マージ不可能なビューでは、ビュー内の最適化アプローチおよび目標のヒントは無視されます。つまり、トップレベルの問合せにより最適化モードが決定されます。
マージ不可能なビューはトップレベルの問合せとは別々に最適化されるため、ビュー内のアクセス・パスおよび結合のヒントは保持されます。同じ理由から、トップレベルの問合せ内のビューに対するアクセス・パス・ヒントは無視されます。
ただし、この場合、マージ不可能なビューは表に類似しているため、トップレベルの問合せ内のビューに対する結合ヒントは保持されます。