SQLクエリにおいて、アクセスパスに関連するHintは、開発者やデータベース管理者がクエリオプティマイザーに対して特定のテーブルをどのように処理するかを指示することを可能にします。これらはクエリ時のデータの読み取り方法に影響します。
ヒントタイプ |
説明 |
|---|---|
DYNAMIC_SAMPLING |
テーブルレベルの動的サンプリングを指定します。 |
FULL |
オプティマイザーに対し、指定されたテーブルに対して主キーを使用した全表スキャンを指示します。 |
INDEX |
指定したテーブルが特定のインデックスを使用するよう指定します。その逆操作は NO_INDEX です。 |
NO_INDEX |
指定したテーブルで特定のインデックスを無効にするよう指定します。その逆操作は INDEX です。 |
INDEX_SS |
指定したテーブルが特定のインデックスを使用し、スキップスキャンを行うよう指定します。 |
PARALLEL |
テーブルレベルの並列度を指定します。 |
USE_DAS |
オプティマイザーに対し、指定したテーブルでDASを使用するよう指示します。その逆操作は NO_USE_DAS です。 |
NO_USE_DAS |
オプティマイザーに対し、指定したテーブルでDASを無効にするよう指示します。その逆操作は USE_DAS です。 |
USE_COLUMN_TABLES |
テーブルオブジェクトに対してカラムストアスキャンを使用するよう指定します。その逆操作は NO_USE_COLUMN_TABLE です。 |
NO_USE_COLUMN_TABLE |
テーブルオブジェクトに対するカラムストアスキャンを禁止します。その逆操作は USE_COLUMN_TABLE です。 |
INDEX_MERGE |
指定したテーブルでインデックスマージ計画を使用するかどうかを制御します。
注意
|
NO_INDEX_MERGE |
指定したテーブルで指定されたインデックスを使用してインデックスマージ計画を生成しないよう制御します。
注意
|
DYNAMIC_SAMPLING ヒント
DYNAMIC_SAMPLING ヒントは、クエリで動的サンプリングを有効にするかどうかを制御します。動的サンプリングを有効にすると、特に統計情報が不足している場合や不正確な場合に、クエリ実行計画の品質が向上します。
構文
/*+DYNAMIC_SAMPLING( [[ qb_name_option ] table_name ] INTNUM1 [, INTNUM2 ] ) */
パラメータの説明
qb_name_option:オプション。Query Blockの名前です。table_name:オプション。動的サンプリングを適用するテーブル名です。空の場合、クエリ全体で動的サンプリングが使用されます。INTNUM1:サンプリングのレベルを指定します(現在は0または1のみサポートしています。1は動的サンプリングを有効にし、0は無効にします)。INTNUM2:サンプリングするマイクロブロック数を指定します(32個以上のマイクロブロックを設定することを推奨します)。
例
-- クエリ時にテーブルt1に対して動的サンプリング機能を使用する
SELECT /*+DYNAMIC_SAMPLING(t1 1)*/ c4 FROM t1 WHERE c1 > 1 AND c2 > 1 AND c3 > 1 GROUP BY c4;
FULL ヒント
FULL ヒントは、オプティマイザーが指定されたテーブルに対して主キースキャンを実行するように有効化します。
構文
/*+ FULL ( [ @queryblock ] tablespec ) */
例
以下のクエリ例では、列 last_name にインデックスが存在しても、クエリは employees テーブルに対して主キースキャンを実行します。FROM 句でエイリアス e を使用して employees テーブルを指定しているため、ヒントで参照されているのはエイリアスであり、テーブルの実際の名前ではありません。
まず、テーブル employees を作成し、必要なデータとインデックスを作成します:
CREATE TABLE hr.employees (
employee_id INT PRIMARY KEY,
last_name VARCHAR(255),
first_name VARCHAR(255)
);
-- いくつかのサンプルデータを挿入
INSERT INTO hr.employees (employee_id, last_name, first_name)
VALUES
(1, 'Smith', 'John'),
(2, 'Doe', 'Jane'),
(3, 'Brown', 'Charlie');
-- インデックスを作成
CREATE INDEX idx_last_name ON hr.employees(last_name);
次に、FULL ヒントを使用して、employees テーブルに対する主キースキャンを強制的に実行します:
-- employees テーブルに対して主キーを使用したスキャンを強制する
SELECT /*+ FULL(e) */ employee_id, last_name
FROM hr.employees e
WHERE last_name LIKE :al;
INDEX ヒント
INDEX ヒントは、指定したテーブルで特定のインデックスを使用するようにオプティマイザーに指示します。その逆操作は NO_INDEX ヒントであり、指定したテーブルで特定のインデックスを無効にすることを意味します。
構文
/*+ INDEX ( [ @queryblock ] tablespec indexspec ) */
動作
ヒントの動作は indexspec の仕様によって異なります:
- 単一のインデックス:1つのヒントでは1つのインデックスのみを指定できます。オプティマイザーはそのインデックスの使用をスキャンの対象として検討し、他のインデックスやテーブル全体のスキャンは考慮しません。
- 複数のヒント:同じテーブルに対して複数のINDEXヒントを記述できます。例えば、
/*+ INDEX(t idx1) INDEX(t idx2) */を使用すると、オプティマイザーは指定されたインデックスを評価し、コストが最も低いインデックスを選択してスキャンします。この場合、リストにないインデックスやテーブル全体のスキャンも検討されません。
単独の INDEX ヒントは1つのインデックスのみを指定できます。同一テーブルの複数のインデックスに対してヒントを提供する場合は、各インデックスごとに個別に INDEX ヒントを記述する必要があります。
例
-- INDEX ヒントを使用して、クエリオプティマイザーに 'emp_department_ix' インデックスを使用して employees テーブルにアクセスするよう指示する
SELECT /*+ INDEX (employees emp_department_ix) */ employee_id, department_id
FROM employees
WHERE department_id > 50;
NO_INDEX ヒント
NO_INDEX ヒントは、指定したテーブルで特定のインデックスの使用を無効にするために使用されます。その逆操作は INDEX ヒントであり、指定したテーブルで特定のインデックスを有効にすることを意味します。
構文
/*+ NO_INDEX ( [ @queryblock ] tablespec indexspec ) */
例
-- NO_INDEX ヒントを使用して、クエリオプティマイザーが 'emp_department_ix' インデックスを使用して employees テーブルにアクセスするのを無効にします。
SELECT /*+ NO_INDEX (employees emp_department_ix) */ employee_id, department_id
FROM employees
WHERE department_id > 50;
INDEX_SS ヒント
INDEX_SS ヒントは、テーブルオブジェクトに対して特定のインデックスを使用してインデックススキップスキャンを実行するよう指定します。
構文
/*+ INDEX_SS ( [ @ qb_name ] tablespec indexspec) */
パラメータの説明
tablespec:ヒントで指定するテーブルオブジェクト。indexspec:INDEX SKIP SCANで使用するインデックス。
例
以下のクエリ例では、インデックス idx1 を使用して index skip scan スキャンを実行するよう指定しており、その結果得られたクエリプランは以下のとおりです。クエリで index skip scan に使用されるサフィックス query range は (1,MIN ; 1,MAX) であり、このサフィックスはインデックス idx1 の2列目 c2 から抽出されます。
create table t1(c1 int, c2 int ,c3 int);
create index idx1 on t1(c1, c2);
create index idx2 on t1(c2);
explain basic select /*+index_ss(t1 idx1)*/ 1 from t1 where c2 = 1;
+-----------------------------------------------------------------------------------------------------+
| Query Plan |
+-----------------------------------------------------------------------------------------------------+
| ============================= |
| |ID|OPERATOR |NAME | |
| ----------------------------- |
| |0 |TABLE SKIP SCAN|t1(idx1)| |
| ============================= |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([1]), filter([t1.c2 = 1]), rowset=16 |
| access([t1.c2]), partitions(p0) |
| is_index_back=false, is_global_index=false, filter_before_indexback[false], |
| range_key([t1.c1], [t1.c2], [t1.__pk_increment]), range(MIN,MIN,MIN ; MAX,MAX,MAX)always true |
| prefix_columns_cnt = 1 , skip_scan_range(1,MIN ; 1,MAX) |
+-----------------------------------------------------------------------------------------------------+
注意点として、INDEX_SS ヒントを使用しても、インデックス上から index skip scan スキャンに使用可能なサフィックス query range を抽出できない場合、クエリは最終的に index skip scan を使用しません。この場合、INDEX_SS ヒントの役割は、クエリが特定のインデックスを使用するよう指定することだけです。
以下の2つの例では、最初のクエリは idx1 インデックスを使用しますが、直接抽出した (1,MIN,MIN ; 1,MAX,MAX) の query range では index skip scan スキャンを実行できません。2番目のクエリは idx2 インデックスを使用しますが、抽出した (1,MIN ; 1,MAX) の query range でも index skip scan スキャンを実行できません。 また、INDEX_SS ヒントには index skip scan の使用を禁止する逆向きのヒントは対応していませんが、INDEX ヒントを直接使用してインデックスを指定することで、index skip scan スキャンを直接禁止できます。
explain basic select /*+index_ss(t1 idx1)*/ 1 from t1 where c1 = 1;
+----------------------------------------------------------------------------------------+
| Query Plan |
+----------------------------------------------------------------------------------------+
| ============================== |
| |ID|OPERATOR |NAME | |
| ------------------------------ |
| |0 |TABLE RANGE SCAN|t1(idx1)| |
| ============================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([1]), filter(nil), rowset=16 |
| access(nil), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([t1.c1], [t1.c2], [t1.__pk_increment]), range(1,MIN,MIN ; 1,MAX,MAX), |
| range_cond([t1.c1 = 1]) |
+----------------------------------------------------------------------------------------+
explain basic select /*+index_ss(t1 idx2)*/ 1 from t1 where c2 = 1;
+-----------------------------------------------------------------------+
| Query Plan |
+-----------------------------------------------------------------------+
| ============================== |
| |ID|OPERATOR |NAME | |
| ------------------------------ |
| |0 |TABLE RANGE SCAN|t1(idx2)| |
| ============================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([1]), filter(nil), rowset=16 |
| access(nil), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([t1.c2], [t1.__pk_increment]), range(1,MIN ; 1,MAX), |
| range_cond([t1.c2 = 1]) |
+-----------------------------------------------------------------------+
PARALLEL ヒント
PARALLEL ヒントはステートメントレベルのヒントであり、オプティマイザーに対して並列処理で使用可能な並列スレッド数を指定するよう指示します。このヒントは、初期化パラメータ PARALLEL_DEGREE_POLICY の値を上書きします。このヒントは SELECT、INSERT、UPDATE、DELETE ステートメントの一部、およびテーブルスキャンの一部として使用できます。いずれかの並列制限に違反した場合、PARALLEL ヒントは無視されます。
構文
テーブルレベルの PARALLEL ヒントの構文は次のとおりです:
/*+ PARALLEL(table_name n) */
ヒントを同時に使用してテーブルレベルとグローバルな並列度を指定する場合、テーブルレベルのヒントが優先されます。
例
-- テーブルをスキャンする際に、並列度8を使用する
SELECT /*+parallel(4) parallel(emp 8) */ last_name
FROM emp;
USE_DAS ヒント
USE_DAS ヒントは、オプティマイザーに対して指定されたテーブルにDAS(Distributed Data Access Service)を使用するよう指示します。これはOceanBaseデータベースで提供されている分散型データアクセスサービスです。USE_DAS ヒントを有効にすることで、ユーザーは以下の効果を実現し、OceanBaseデータベースの利点を最大限に活用できます:
パーティションプルーニング機能:データと物理ノード間のマッピング関係を維持することで、DASはオプティマイザーがSQLリクエストの実行時に必要な物理位置情報を計算するのを支援し、クエリ効率を向上させ、不必要なデータスキャンを削減します。
効率的な基盤データアクセス:DASは、挿入(insert)、更新(update)、削除(delete)、行のロック(lock_row)、およびスキャン(scan)などの一般的なデータベース操作をサポートします。これにより、分散環境全体でのデータへの効率的なアクセスが保証され、SQLリクエストが任意のObserverノード上でクラスタ内の各ノードのデータに柔軟にアクセスできるようになります。
タスクレベルの再試行機能:データアクセスの実行時に、レプリカの移行やネットワークパーティショニングなどの原因で特定のパーティションが読み取り不可になった場合、DASは自動的に他の利用可能なレプリカからリクエストを再試行します。
構文
/*+ USE_DAS ( [ @queryblock ] tablespec ) */
例
SELECT /*+ USE_DAS(t1) */ * FROM t1 WHERE column1 > 100;
NO_USE_DAS ヒント
NO_USE_DAS ヒントは、オプティマイザーに対し、指定されたテーブルのクエリ処理時にDASを使用しないよう指示します。その逆操作は USE_DAS です。
構文
/*+ NO_USE_DAS ( [ @queryblock ] tablespec ) */
例
-- `NO_USE_DAS` ヒントは、オプティマイザーに対し、テーブルt1に対して動的適応型サンプリングを実行せず、既存の統計情報に基づいてクエリを実行するよう通知します。
SELECT /*+ NO_USE_DAS(t1) */ * FROM t1 WHERE column1 < 50;
USE_COLUMN_TABLE ヒント
USE_COLUMN_TABLE ヒントは、テーブルオブジェクトに対してカラムストアスキャンを使用するよう指定します。カラムストアが有効になっていないテーブルでは、USE_COLUMN_TABLE の使用は無効です。
構文
/*+ USE_COLUMN_TABLE ( [ @ qb_name ] tablespec) */
例
create table t(c1 int, c2 int ,c3 int)
with column group (all columns, each column);
explain basic select /*+USE_COLUMN_TABLE(t)*/ * from t;
+------------------------------------------------------------------+
| Query Plan |
+------------------------------------------------------------------+
| ================================ |
| |ID|OPERATOR |NAME| |
| -------------------------------- |
| |0 |COLUMN TABLE FULL SCAN|t | |
| ================================ |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t.c1], [t.c2], [t.c3]), filter(nil), rowset=16 |
| access([t.c1], [t.c2], [t.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([t.__pk_increment]), range(MIN ; MAX)always true |
+------------------------------------------------------------------+
NO_USE_COLUMN_TABLE ヒント
NO_USE_COLUMN_TABLE ヒントは、テーブルオブジェクトに対するカラムストアスキャンの使用を禁止するよう指定します。
構文
/*+ NO_USE_COLUMN_TABLE ( [ @ qb_name ] tablespec ) */
例
create table t(c1 int, c2 int ,c3 int)
with column group (all columns, each column);
explain basic select /*+NO_USE_COLUMN_TABLE(t)*/ * from t;
+------------------------------------------------------------------+
| Query Plan |
+------------------------------------------------------------------+
| ========================= |
| |ID|OPERATOR |NAME| |
| ------------------------- |
| |0 |TABLE FULL SCAN|t | |
| ========================= |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([t.c1], [t.c2], [t.c3]), filter(nil), rowset=16 |
| access([t.c1], [t.c2], [t.c3]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([t.__pk_increment]), range(MIN ; MAX)always true |
+------------------------------------------------------------------+
INDEX_MERGE ヒント
INDEX_MERGE ヒントは、指定されたテーブルがインデックスマージ計画を使用するかどうかを制御します。指定されたインデックスがインデックスマージ計画を生成できない場合はこのヒントが無視されますが、インデックスが指定されていない場合は可能な限りインデックスマージ計画を試みます。
INDEX_MERGE ヒントを使用することで、_enable_index_merge 構成パラメータの値が False の場合でもインデックスマージ計画を生成できます。
構文は以下のとおりです:
/*+ INDEX_MERGE([@query_block_name] tbl_name [index_name [,index_name]...]) */
パラメータの説明:
@query_block_name:オプションです。このヒントが適用されるクエリブロック(query block)の名前を表します。省略した場合、デフォルトで現在のクエリのメインクエリブロックに適用されます。tbl_name:インデックスマージ計画を適用するテーブル名を表します。index_name:オプションです。インデックスマージ計画に参加するインデックス名を表します。複数のインデックス名を指定できます。- 指定されたテーブルの後に
index_nameパラメータがない場合、指定されたテーブルがインデックスマージ計画を使用するように制御します。 - 指定されたテーブルの後に
index_nameパラメータがある場合、指定されたテーブルが指定されたインデックス(Index)を使用してインデックスマージ計画を生成するように制御します。
- 指定されたテーブルの後に
例:
INDEX_MERGEヒントでインデックス名を指定します。obclient> SELECT /*+ INDEX_MERGE(t1 idx_c2 idx_c3) */ * FROM t1 WHERE c2 = 1 AND c3 = 1 AND c4 = 1;INDEX_MERGEヒントでインデックス名を指定しません。obclient> SELECT /*+ INDEX_MERGE(t1)*/ * FROM t1 WHERE c2 = 1 AND c3 = 1 AND c4 = 1;
NO_INDEX_MERGE ヒント
NO_INDEX_MERGE ヒントは、指定されたテーブルが指定されたインデックスを使用してインデックスマージ計画を生成しないように制御します。インデックスが指定されていない場合、そのテーブルがインデックスマージ計画を生成することを禁止します。
NO_INDEX_MERGE ヒントと INDEX_MERGE ヒントが競合する場合、これら2つのヒントは無視されます。
構文は以下のとおりです:
/*+ NO_INDEX_MERGE([@query_block_name] tbl_name [index_name [,index_name]...]) */
パラメータの説明:
@query_block_name:オプションです。このヒントが適用されるクエリブロック(query block)の名前を表します。省略した場合、デフォルトで現在のクエリのメインクエリブロックに適用されます。tbl_name:テーブル名を表します。index_name:オプションです。インデックス名を表します。複数のインデックス名を指定できます。- 指定されたテーブルの後に
index_nameパラメータがない場合、インデックスマージ計画を使用しないことを意味します。 - 指定されたテーブルの後に
index_nameパラメータがある場合、指定されたインデックス(Index)を使用してインデックスマージ計画を生成しないことを意味します。
- 指定されたテーブルの後に
例:
obclient> SELECT /*+ NO_INDEX_MERGE(t1)*/ * FROM t1
WHERE c2 = 1
AND c3 = 1
AND c4 = 1;