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_TABLE |
テーブルオブジェクトに対してカラムストアスキャンを使用するよう指定します。その逆操作は NO_USE_COLUMN_TABLE です。 |
NO_USE_COLUMN_TABLE |
テーブルオブジェクトに対するカラムストアスキャンを禁止します。その逆操作は USE_COLUMN_TABLE です。 |
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:インデックススキップスキャンで使用するインデックス。
例
以下のクエリ例では、クエリがインデックスidx1を使用してindex skip scanを実行するよう指定されており、その結果得られるクエリプランは次のとおりです。クエリ内でindex skip scanに使用されるサフィックスquery rangeは(1,MIN ; 1,MAX)であり、このサフィックスquery rangeはインデックス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 |
+------------------------------------------------------------------+