オプティマイザ・ヒントを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言語リファレンス』を参照してください。 |
次のヒントでは、最適化アプローチと目標のいずれかを選択できます。
最適化アプローチと目標を指定するヒントが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
)ヒントとともに、アクセス・パスまたは結合操作のヒントを指定した場合、オプティマイザはヒントによって指定されたアクセス・パスと結合操作を優先します。
マージ可能なビューでのヒントの動作については、「ビューでの最適化アプローチと目標のヒント」を参照してください。
次の各ヒントでは、オプティマイザが表の特定のアクセス・パスを使用するように指示します。
FULL
CLUSTER
HASH
INDEX
NO_INDEX
INDEX_ASC
INDEX_COMBINE
INDEX_JOIN
INDEX_DESC
INDEX_FFS
NO_INDEX_FFS
INDEX_SS
INDEX_SS_ASC
INDEX_SS_DESC
NO_INDEX_SS
これらのヒントの1つを指定すると、指定されたアクセス・パスが索引やクラスタの存在およびSQL文の構文構造体に基づいて使用できる場合のみ、オプティマイザはそのアクセス・パスを選択します。ヒントを使用できないアクセス・パスを指定すると、オプティマイザはその指定を無視します。
アクセスする表は、文に指定する場合と同じように正確に指定してください。文が表の別名を使用している場合、表の名前ではなく、表の別名をヒントで使用する必要があります。スキーマ名が文中にある場合は、ヒント内の表名にそのスキーマ名を入れないでください。
マージ可能なビューでのヒントの動作については、「ビューに対するアクセス・パスとヒント結合」および「ビューの内側のアクセス・パスとヒント結合」を参照してください。
注意: アクセス・パスのヒントの場合、SELECT 文のFROM 句でSAMPLE オプションを指定すると、Oracleはヒントを無視します。 |
関連項目: SAMPLE オプションの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。 |
次の各ヒントでは、オプティマイザが表の特定の結合操作を使用するように指示します。
USE_NL
ヒントとUSE_MERGE
ヒントは、結合順序のヒントとともに使用することをお薦めします。「結合順序のヒント」を参照してください。Oracleでは、参照表が結合の内部表になった場合にこれらのヒントを使用し、参照表が外部表の場合にはこれらのヒントを無視します。
マージ可能なビューでのヒントの動作については、「ビューに対するアクセス・パスとヒント結合」および「ビューの内側のアクセス・パスとヒント結合」を参照してください。
次のヒントでは、パラレル実行を行ったときに、文がどのようにパラレル化されるか、またはパラレル化されないかについてオプティマイザを指示します。
マージ可能なビューでのヒントの動作については、「ビューに対するパラレル実行ヒント」および「ビューの内側のパラレル実行ヒント」を参照してください。
関連項目: パラレル実行の詳細は、『Oracle Databaseデータ・ウェアハウス・ガイド』を参照してください。 |
ヒントは、それらが含まれるSQL文ブロックの最適化のみに適用されます。文ブロックは、次のいずれかの文または文の一部です。
単純なSELECT
文、UPDATE
文またはDELETE
文
複合文の親文または副問合せ
複合問合せの一部
たとえば、UNION
演算子で結合した2つの構成要素の問合せから成る複合問合せには、各構成要素の問合せに対して1つずつ、合計2つのブロックがあります。このため、この最初の構成要素の問合せにおけるヒントはその最適化のみに適用され、2番目の構成要素の問合せの最適化には適用されません。
次の各項では、ヒントの使用方法をさらに詳しく説明します。
ヒントを使用するとき、ある状況では、最適な実行計画を確認するためにヒントの全セットの指定が必要な場合があります。たとえば、多数の表が結合された非常に複雑な問合せが存在するときに、指定の表に対してINDEX
ヒントのみを指定すると、オプティマイザは、使用される残りのアクセス・パスとともに、対応する結合方法も判断する必要があります。したがって、INDEX
ヒントを指定しても、オプティマイザによってそのヒントが使用されるとはかぎりません。これは、オプティマイザの選択した結合方法およびアクセス・パスによっては、要求された索引を使用できないとオプティマイザが判断するためです。
例19-1では、LEADING
ヒントにより、使用する正確な結合順序が、別の表で使用される結合方法とともに指定されています。
例19-1 ヒント全セットの指定方法
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
ヒントにより設定できます。
例19-2では、ビュー上のSELECT
文内の問合せブロックを指定するため、問合せブロック名がNO_UNNEST
ヒントとともに使用されています。
例19-2 ヒントにおける問合せブロックの使用方法
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;
問合せにEXPLAIN PLAN
を実行し、PLAN TABLE出力を表示した後、システム生成の問合せブロック識別子を決定できます。たとえば、問合せブロック名は次のPLAN TABLE出力に表示されます。
SELECT PLAN_TABLE_OUTPUT
FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'SERIAL'));
...
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
...
10 - SEL$4 / E2@SEL$4
問合せブロック名が決定された後は、これを次のSQL文に使用できます。
SELECT /*+ NO_UNNEST( @SEL$4 ) */
*
FROM v;
表を指定するヒントは、一般に、ヒントが呼び出される場所であるDELETE
、SELECT
またはUPDATE
問合せブロック内の表を参照します。文によって参照されるビュー内の表は参照しません。ビュー内に表示される表のヒントを指定する場合は、ビューに埋め込まれているヒントではなくグローバル・ヒントを使用することをお薦めします。この章で説明する表ヒントは、表の名前とともにビューの名前が含まれる拡張tablespec
構文を使用して、グローバル・ヒントに変換できます。
また、tablespec
構文の前にオプションの問合せブロック名を使用できます。「ヒントにおける問合せブロックの指定方法」を参照してください。
表を指定するヒントには、次の構文を使用します。
tablespec::=
図tablespec.gifの説明
各項目は次のとおりです。
view
は、ビュー名を指定します。
table
は、表の名前または別名を指定します。
ビューのパスが指定されている場合、ヒントは左から右へ解決されます。この場合、1つ目のビューはFROM
句に含まれる必要があり、それ以降の各ビューは、前のビューのFROM
句で指定されている必要があります。
たとえば、例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;
グローバル・ヒント構文は、例19-4に示すように、マージ不可能なビューにも適用されます。
例19-4 NO_MERGEを含むグローバル・ヒントの使用方法
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;
ビュー(または副問合せ)内、またはビューに対してのヒントの使用は、お薦めしません。これは、1つのコンテキストに定義したビューを他のコンテキストでも使用できるためです。また、このようなヒントによって予想外の実行計画が発生する可能性があります。特に、ビュー内のヒントまたはビューに対するヒントは、そのビューがトップレベルの問合せにマージ可能かどうかによって処理方法が異なります。
表のヒントをビューまたは副問合せ内で指定する場合は、グローバル・ヒント構文の使用をお薦めします。「グローバル表のヒントの指定方法」を参照してください。
それでも、ビューでヒントを使用する場合は、この後の項で状況ごとの動作についての説明を参照してください。
デフォルトでは、複合ビューでヒントは使用できません。たとえば、複合ビューに対して選択する問合せでヒントを指定しても、そのヒントは機能しません。これは、ビュー内にヒントがプッシュされないためです。
注意: ビューが単一表の場合、ヒントは伝播されません。 |
ヒントがベース・ビュー内に存在しないかぎり、ビューに対する問合せからヒントが機能することはありません。
この項では、マージ可能なビューでのヒントの動作について説明します。
ビューでの最適化アプローチと目標のヒント
最適化アプローチと目標のヒントは、トップレベルの問合せまたはビューの内側に指定できます。
そのようなヒントがトップレベルの問合せにある場合は、ビューの内側にあるヒントとは関係なくそのヒントが使用されます。
トップレベルのオプティマイザ・モード・ヒントがない場合は、参照されているビューのすべてのモード・ヒントに一貫性があるかぎり、それらのモード・ヒントが使用されます。
参照されているビューの2つ以上のモード・ヒントが矛盾する場合は、そのビューのすべてのモード・ヒントが廃棄されて、セッション・モードが使用されます(デフォルトかユーザー指定かには関係しません)。
ビューに対するアクセス・パスとヒント結合
参照されるビューに対するアクセス・パスとヒント結合は、そのビューが単一の表を含んでいないかぎり(または単一の表を持つその他のヒント・ビューを参照していないかぎり)無視されます。そのような単一表ビューでは、ビューに対するアクセス・パスやヒント結合は、そのビューの中の表に対して適用されます。
ビューの内側のアクセス・パスとヒント結合
アクセス・パスとヒント結合は、ビュー定義に含めることができます。
ビューがインライン・ビューである場合(つまり、ビューがSELECT
文のFROM
句にある場合)、そのビューの内側のすべてのアクセス・パスとヒント結合は、そのビューがトップレベルの問合せにマージされるときに保存されます。
インライン・ビューでないビューでは、そのビューの中のアクセス・パスとヒント結合が保存されるのは、参照問合せが他の表やビューを参照していない場合(つまり、SELECT
文のFROM
句にそのビューしか含まれていない場合)のみです。
ビューに対するパラレル実行ヒント
ビューに対するPARALLEL
、NO_PARALLEL
、PARALLEL_INDEX
およびNO_PARALLEL_INDEX
ヒントは、参照されるビュー内のすべての表に繰り返し適用されます。トップレベルの問合せのパラレル実行ヒントは、参照されるビューの内側のそのようなヒントを上書きします。
ビューの内側のパラレル実行ヒント
ビューの内側のPARALLEL
、NO_PARALLEL
、PARALLEL_INDEX
およびNO_PARALLEL_INDEX
ヒントは、ビューがトップレベルの問合せにマージされるときに保存されます。トップレベルの問合せにあるビューのパラレル実行ヒントは、参照されるビューの内側のそのようなヒントを上書きします。
マージ不可能なビューでは、ビューの内側の最適化アプローチと目標のヒントは無視されます。つまり、トップレベルの問合せにより最適化モードが決定されます。
マージ不可能なビューはトップレベルの問合せとは別に最適化されるので、そのビューの内側のアクセス・パスとヒント結合は保存されます。同じ理由から、トップレベルの問合せ内のビューに対するアクセス・パスも無視されます。
ただし、トップレベルの問合せ内のビューに対するヒント結合は保存されます。この場合、マージ不可能なビューは表と同様であるためです。