ヒントとは、SQL文のコメントであり、OceanBaseデータベースのオプティマイザーに指示を伝えるために使用されます。ヒントを使用することで、オプティマイザーが指定された実行計画を生成するようになります。
通常、オプティマイザーはユーザーのクエリに対して最適な実行計画を選択します。そのため、ユーザーがヒントを使用して指定する必要はありません。ただし、オプティマイザーが生成した実行計画がユーザーの要件を満たさない可能性がある場合は、ユーザーがヒントを使用して特別な実行計画を明示的に指定し、生成する必要があります。
注意すべき点として、関連するテーブルの統計情報を収集し、ヒントなしでEXPLAIN PLANステートメントを使用してオプティマイザーの計画を評価した後にのみ、ヒントの使用を慎重に検討することを推奨します。データベースの条件を変更したり、今後のバージョンでクエリ性能が向上したりすると、コード内のヒントがパフォーマンスに大きな影響を与える可能性があります。
ヒントの使用方法
ヒントの使用方法と注意点
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 Hint)、およびオプティマイザーヒント(Optimizer Hint)に細分化され、それぞれのヒントはオプティマイザー内での役割に応じて異なる分類があります。
グローバルヒント(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ヒントを使用して明示的に指定されることもあります。クエリブロックヒントを使用してヒントの適用範囲や対象を指定する方法など、クエリブロック名とQB_NAMEヒントの詳細については、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ヒントが現在のクエリブロックの名前を指定するために使用される以外、他のヒントはそれぞれオプティマイザーのクエリ書き換え段階と計画生成段階で機能します。トランスフォームヒントはクエリ書き換え行為に、オプティマイザーヒントは計画生成行為に影響を与えます。