HintはSQL文のコメントであり、OceanBaseデータベースのオプティマイザーに指示を伝えるために使用されます。Hintを使用することで、オプティマイザーに特定の実行計画の生成を指示できます。
通常、オプティマイザーはユーザーのクエリに対して最適な実行計画を選択します。そのため、ユーザーがHintで指定する必要はありません。ただし、オプティマイザーが生成した実行計画がユーザーの要件を満たせない可能性がある場合は、ユーザーがHintを使用して特別な実行計画を明示的に指定・生成する必要があります。
なお、関連テーブルの統計情報が収集されており、Hintを使用せずにEXPLAIN PLANステートメントでオプティマイザーの計画を評価した後であれば、Hintの使用を慎重に検討することを推奨します。データベースの条件変更や今後のバージョンでのクエリパフォーマンス向上により、コード内のHintがパフォーマンスに大きな影響を及ぼす可能性があります。
ヒントの使用方法
ヒントの使用方法と注意点
1文には1つのヒントコメントしか含めることができず、そのコメントは CREATE、SELECT、UPDATE、INSERT、REPLACE または DELETE キーワードの後に続けなければなりません。ヒントはオプティマイザーが生成する実行計画のロジックにのみ影響を及ぼし、SQL文の意味には影響しません。
- 文内コメントにおけるヒントの構文は以下のとおりです:
{CREATE|DELETE|INSERT|SELECT|UPDATE|REPLACE} /*+ hint_text [,hint_text...] */
ヒントを定義する際の注意事項:
ヒントは構文的には特殊なSQLコメントであり、コメントは
/*+で始まり、スペースは許容されません。サーバー側がSQL文内のヒントを認識できない場合、オプティマイザーはユーザーが指定したヒントを無視し、デフォルトの計画で生成された実行ロジックを使用します。
各
SELECTなどのキーワードの後には、1つのヒントセクションのみを追加できます。このヒントセクション内部には複数のヒントを含めることができます。ヒントコメントの/*+の+とヒントテキストの間にはスペースを入れても入れなくてもかまいません。コメント内に複数のヒントが含まれる場合、ヒント間は少なくとも1つのスペースで区切る必要があります。以下の例では、
/*+ hint1 */と/*+ hint3 hint4 */は有効なヒントであり、/*+ hint2 */は無効なヒントです。select /*+ hint1 */ /*+ hint2 */ * from t1, (select /*+ hint3 hint4 */ t2.* from t2, t3) v where t1.c1 = v.c1;ヒントを追加できる複数の位置が存在するクエリでは、クエリ内で複数のヒントセクションを使用できます。
スペルミスや構文エラーを含むヒントは無視されます。ただし、データベースは同じコメント内で他の正しく指定されたヒントの使用を検討します。
CREATE、DELETE、INSERT、REPLACE、SELECTまたはUPDATEキーワードの後に続かないヒントは無効です。ヒントの組み合わせが互いに競合する場合、ヒントは無効です。ただし、データベースは同じコメント内で他の競合しないヒントの使用を検討します。
ヒントはコメントとしてクエリに追加されるため、一部のクライアント/ドライバーはクエリ内のコメントを削除し、ヒントを無効にする可能性があります。
ヒント内でクエリブロックを定義する
多くのヒントでは、オプションのクエリブロック名を定義することで、そのヒントが適用されるクエリブロックを指定できます。詳細については、Query Block Name と QB_NAME ヒントを使用したクエリ最適化の制御を参照してください。
この構文を使用することで、外部クエリ内で、埋め込みビューに適用されるヒントを指定できます。
クエリブロックパラメータの構文は @queryblock であり、ここで queryblock はクエリ内で指定されたクエリブロックの識別子です。queryblock 識別子はシステム生成のものでも、ユーザーが自ら指定したものでもかまいません。クエリブロック内で直接適用するヒントを指定する場合、@queryblock は無視されます。
システム生成の識別子は、クエリに
EXPLAINを実行することで生成できます。QB_NAME を使用して、ユーザー定義の名前を指定できます。
ヒントの分類と役割
OceanBaseデータベースのヒントは、主にグローバルヒント(Global Hint)とクエリブロックヒント(Query Block Hint)の2種類に分類されます。
クエリブロックヒントは、さらにQB_NAMEヒント、Transformヒント、Optimizerヒントに細分化され、各ヒントはオプティマイザー内での役割に応じて異なる分類がされます。
グローバルヒント(Global Hint)
グローバルヒントはクエリ全体に作用し、クエリ内での位置に関係なく常に同じ効果を発揮します。例えば、以下の2つのクエリで使用されている並列実行ヒントは等価です:
select /*+ parallel(8) */ * from ( select * from t1);
select * from ( select /*+ parallel(8) */ * from t1);
グローバルヒントの定義
グローバルヒントは特定のテーブルやインデックスに対しても、より広範囲にわたってビュー内のテーブルやインデックスの一部に適用することもできます。tablespec と indexspec を使用して、グローバルヒントの作用対象を定義できます:
tablespec:グローバルヒントが作用するテーブルを定義します。ヒントを使用する際には、クエリステートメントに表示されているテーブル名またはエイリアスに厳密に従う必要があります。クエリでテーブルのエイリアスが使用されている場合、ヒントでも対応するエイリアスを使用する必要があります。[ view.[, view. ]... ] table_name注意:クエリにスキーマ名が含まれていても、ヒントにはスキーマ名を含めないでください。
注意:ANSI接続を使用するクエリでは、
tablespec句で指定されたグローバルヒントは無効です。これは、オプティマイザーが解析プロセスで追加のビューを生成するためです。この場合、@queryblockを使用してクエリブロックのヒントを指定する必要があります。indexspec:グローバルヒントが作用するインデックスを定義します。ヒントを説明する際、tablespecの後にindexspecを続けることができ、カンマで区切ったテーブル名とインデックス名の指定はオプションです。{ index | ( [ table. ] column_name [ [ table. ] column_name ]... ) }
クエリブロックヒント(Query Block Hint)
OceanBaseオプティマイザーがクエリを解析する際、クエリの構造に基づいて複数のクエリブロックに分割します。各クエリブロックには独自のクエリブロック名(Query Block Name)が付与されます。クエリブロック名はオプティマイザーが自動生成することも、QB_NAMEヒントで明示的に指定することもできます。クエリブロックヒントを使用してヒントの作用範囲や対象を指定する方法など、Query Block NameとQB_NAME Hintの詳細については、Query Block NameとQB_NAME Hintを参照してください。
例えば、以下のクエリでは、外部クエリブロックの名前は qb1、インラインビュー v 内のクエリブロックの名前は qb2 です:
select /*+ qb_name(qb1) */ * from ( select /*+ qb_name(qb2) */ * from t1 ) v;
クエリブロックヒントは特定のクエリブロック内でのみ有効です。クエリブロックヒントを指定して有効にする方法は2つあります:
- ヒントを直接、指定したクエリブロックに追加します。
- ヒント内にクエリブロック名を指定します。構文は
Hint_Name(@qb_name ...)です。
例えば、以下のクエリでは、no_merge ヒントは直接クエリブロック qb2 に追加され、そのブロック内で有効になります。index(@qb2 t1 idx) ヒントはクエリブロック qb1 に追加され、クエリブロック名を指定することでクエリブロック qb2 内で有効になります:
select /*+ index(@qb2 t1 idx) qb_name(qb1) */ *
from ( select /*+ no_merge qb_name(qb2) */ * from t1 ) v;
クエリブロックヒントでは、QB_NAMEヒントが現在のクエリブロック名を指定するために使用される以外、他のヒントはそれぞれオプティマイザーのクエリリライト段階と計画生成段階で機能します:Transformヒントはクエリリライトの動作に介入し、Optimizerヒントは計画生成の動作に介入します。