本記事では、OceanBaseデータベースにおけるHINTの使用規範について説明します。
HINTはできるだけ控えめに使用し、関連するテーブルの統計情報を収集し、HINTなしでステートメントを評価した後にオプティマイザーの実行計画が得られた場合にのみ慎重に検討してください。データベースの条件を変更したり、今後のバージョンでクエリのパフォーマンスを向上させたりすることで、コード内のHINTがパフォーマンスに大きな影響を与える可能性があります。
HINTの紹介
コストベースのオプティマイザーであり、OracleのHINTと類似しています。
サーバー側がSQL文内のHINTを認識できない場合、エラーを報告せずに直接無視します。
HINTはデータベースオプティマイザーが計画を生成するロジックにのみ影響を及ぼし、SQL文自体の意味には影響しません。
HINTは一種の仕組みであり、HINTを使用することでオプティマイザーに特定の計画の生成を指示できます。通常、オプティマイザーはユーザーのクエリに対して最適な実行計画を選択しますので、ユーザーがHINTで指定する必要はありません。しかし、場合によってはオプティマイザーが生成する実行計画がユーザーの要件を満たさないことがあります。そのような場合、ユーザーはHINTを使用して特定の実行計画の生成を明示的に指示する必要があります。
HINT構文
{CREATE|DELETE|INSERT|SELECT|UPDATE|REPLACE} /*+ [HINT_text][hin_text]... */
一つのステートメントブロックには、HINTを含むコメントは一つしか存在できません。また、そのコメントはSELECT、UPDATE、INSERT、MERGE、またはDELETEキーワードの後に続けて記述する必要があります。
構文的に見ると、HINTは特殊なSQLコメントですが、コメントの左側のマーカー(
'/*'記号)の後に'+'が追加されている点が異なります。コメントである以上、サーバー側がSQL文内のHINTを認識できない場合、オプティマイザーはユーザーのHINTを無視し、デフォルトの計画生成ロジックを使用することを選択します。また、HINTはオプティマイザーが計画を生成するロジックにのみ影響を及ぼし、SQL文の意味には影響しません。HINTを定義する際に注意が必要ないくつかのルール:
プラス記号
'+'は、データベースにコメントをHINTリストとして解釈させます。プラス記号はコメントの左側のマーカーの直後に続けて記述する必要があり、スペースは許容されません。プラス記号
'+'とHINTテキストの間のスペースはオプションです。コメントに複数のHINTが含まれる場合、HINT同士は少なくとも1つのスペースまたはカンマで区切る必要があります。スペルミスや構文エラーが含まれる場合は無視されます。ただし、データベースは同一コメント内で他に正しく指定されたHINTを考慮します。
DELETE、INSERT、MERGE、SELECT、またはUPDATEキーワードの後に続かないHINTは無効です。
OceanBaseとOracleでは、HINTの概念が一致しない点以外にも、以下の違いがあります:
- Oracleのleading HINTでは、存在しないテーブルが出現した場合、HINTが有効かどうかが推定され、動作が不安定になります。場合によっては有効で、場合によってはすべて無効になることがあります。
HINTの使用例
パラメータなしの場合、例えば
/*+ KAKA */。パラメータ付きの場合、例えば
/*+ HAHA(param) */。複数のHINTは同一のコメント内に記述でき、カンマまたは少なくとも1つのスペースで区切ります。例:
/*+ KAKA, HAHA(param)*/。SELECT文のHINTは、SELECTキーワードの直後、他の語の前に記述する必要があります。例:
SELECT /*+ KAKA */。UPDATE、DELETE文のHINTは、UPDATE、DELETEキーワードの直後に記述する必要があります。例:
UPDATE /*+ KAKA */、DELETE /*+ KAKA */。
よく使われるHINTの種類
ヒント名 |
ヒントパラメータ |
ヒントの意味 |
|---|---|---|
| NO_REWRITE | SQLをリライトしない。 | |
| READ_CONSISTENCY | weak|strong|frozen | weak:弱い整合性読み取り strong:強い整合性読み取り frozen:最後にフリーズした時点のデータを読む |
| INDEX_HINT | [ qb_name ] table_nameindex_name | クエリテーブル指定時に選択するインデックスを指定します。 |
| QUERY_TIMEOUT | int64 | ステートメント実行のタイムアウト時間を指定します。単位はマイクロ秒(us)です。 |
| LEADING | [ qb_name ] table_name [, table_name ] | 複数テーブル結合時の順序を指定します。 |
| ORDERED | 複数テーブル結合の順序をSQLにおけるテーブル出現順に指定します。 | |
| FULL | [qb_name] table_name | テーブルへのアクセス方式をフルテーブルスキャンとして指定します(主キーがある場合は主キーを読みます)。 |
| USE_MERGE | [qb_name] table_name [,table_name] | 複数テーブル結合時にMERGEアルゴリズムを使用することを指定します。 |
| USE_NL | [ qb_name ] table_name [, table_name] | 複数テーブル結合時にNEST LOOPアルゴリズムを使用することを指定します。 |
| USE_BNL | [qb_name] table_name [,table_name] | 複数テーブル結合時にBLOCK NEST LOOPアルゴリズムを適用することを指定します。 |
| USE_HASH_AGGREGATION | [ qb_name] | aggregateメソッドでHASH AGGREGATEを使用することを指定します。例:HASH GROUP BY、HASH DISTINCT。 |
| NO_USE_HASH_AGGREGATION | [ qb_name ] | aggregateメソッドでHASH AGGREGATEを使用せず、MERGE GROUP BYやMERGE DISTINCTを使用するよう指定します。 |
| QB_NAME | [ qb_name] | クエリブロックの名前を指定します。 |
| PARALLEL | int64 | 分散実行の並列度を指定します。 |
| DISABLE_TRIGGER | trigger_name | DMLで指定されたトリガーを無効にするために使用します。 |
その他のHINTに関する詳細は、SQLチューニングガイドを参照してください。