SQLクエリにおいて、結合順序に関連するHintにはORDERED HintとLEADING Hintがあります。
ヒントタイプ |
説明 |
|---|---|
LEADING |
ヒントで指定されたテーブルの順序で結合します。FROM 句で一部のテーブルのみが指定されている場合、指定されたテーブルがドライバーテーブルとして他のテーブルと結合します。 |
ORDERED |
FROM 句の順序でテーブルを結合します。 |
注意
LEADING Hintを使用して、希望の結合順序を直接明示的に指定することを推奨します。ORDERED Hintは特定の結合順序のみを指定でき、かつ結合順序はリライトの影響を受けるためです。
LEADING ヒント
LEADING ヒントは、オプティマイザーに対して指定された順序でテーブルを結合するよう指示します。ORDERED ヒントよりも柔軟性が高く、LEADING ヒントでは任意の有効な期待結合順序を明示的に定義できます。一方、ORDERED ヒントでは特定の結合順序のみを指定でき、結合順序はリライトの影響を受けます。期待される結合順序を直接明示的に指定するには、LEADING ヒントの使用を推奨します。
構文
/*+ LEADING ( [ @queryblock ] tablespec [ tablespec ]... ) */
使用方法と注意事項
LEADING ヒントは、指定されたテーブル名がクエリ内で出現するテーブル名と完全に一致する場合にのみ有効になります。
ヒントで指定された
table_nameが存在しない場合、LEADINGヒントは無効になります。ヒント内に重複するテーブルが存在する場合、
LEADINGヒントは無効になります。オプティマイザーの結合処理中に対応するテーブルが見つからない場合、そのテーブル以降に指定された結合順序は無効になり、そのテーブルより前に指定された順序は引き続き有効です。
結合グラフ内の依存関係により、指定された順序で最初に指定されたテーブルを結合できない場合、
LEADINGヒントは無効になります。互いに競合する
LEADINGヒントを2つ以上指定した場合、LEADINGヒントは無効になります。ORDEREDヒントを指定した場合、それはすべてのLEADINGヒントを上書きします。
例
SELECT /*+ LEADING(e j) */ *
FROM employees e, departments d, job_history j
WHERE e.department_id = d.department_id
AND e.hire_date = j.start_date;
-- 実行計画の確認
EXPLAIN SELECT /*+ LEADING(e j) */ *
FROM employees e, departments d, job_history j
WHERE e.department_id = d.department_id
AND e.hire_date = j.start_date;
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| =================================================== |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| |
| --------------------------------------------------- |
| |0 |HASH JOIN | |3 |16 | |
| |1 |├─HASH JOIN | |3 |10 | |
| |2 |│ ├─TABLE FULL SCAN|E |3 |5 | |
| |3 |│ └─TABLE FULL SCAN|J |3 |4 | |
| |4 |└─TABLE FULL SCAN |D |3 |4 | |
| =================================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([E.EMPLOYEE_ID], [E.FIRST_NAME], [E.LAST_NAME], [E.HIRE_DATE], [E.DEPARTMENT_ID], [D.DEPARTMENT_ID], [D.DEPARTMENT_NAME], [J.EMPLOYEE_ID], |
| [J.START_DATE], [J.END_DATE], [J.JOB_ID]), filter(nil), rowset=16 |
| equal_conds([E.DEPARTMENT_ID = D.DEPARTMENT_ID]), other_conds(nil) |
| 1 - output([E.EMPLOYEE_ID], [E.FIRST_NAME], [E.LAST_NAME], [E.HIRE_DATE], [E.DEPARTMENT_ID], [J.EMPLOYEE_ID], [J.START_DATE], [J.END_DATE], [J.JOB_ID]), filter(nil), rowset=16 |
| equal_conds([E.HIRE_DATE = J.START_DATE]), other_conds(nil) |
| 2 - output([E.EMPLOYEE_ID], [E.DEPARTMENT_ID], [E.HIRE_DATE], [E.FIRST_NAME], [E.LAST_NAME]), filter(nil), rowset=16 |
| access([E.EMPLOYEE_ID], [E.DEPARTMENT_ID], [E.HIRE_DATE], [E.FIRST_NAME], [E.LAST_NAME]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([E.EMPLOYEE_ID]), range(MIN ; MAX)always true |
| 3 - output([J.START_DATE], [J.EMPLOYEE_ID], [J.END_DATE], [J.JOB_ID]), filter(nil), rowset=16 |
| access([J.START_DATE], [J.EMPLOYEE_ID], [J.END_DATE], [J.JOB_ID]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([J.__pk_increment]), range(MIN ; MAX)always true |
| 4 - output([D.DEPARTMENT_ID], [D.DEPARTMENT_NAME]), filter(nil), rowset=16 |
| access([D.DEPARTMENT_ID], [D.DEPARTMENT_NAME]), partitions(p0) |
| is_index_back=false, is_global_index=false, |
| range_key([D.DEPARTMENT_ID]), range(MIN ; MAX)always true |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
28 rows in set
上記の実行計画では、LEADING(e j) はオプティマイザーに対し、まずテーブル e (employees) を優先的に考慮し、次にテーブル j (job_history) を考慮するよう指示します。
ORDERED ヒント
クエリでデフォルトの結合順序を使用します。ORDERED ヒントは LEADING ヒントよりも優先順位が高く、ORDERED ヒントが存在する場合、LEADING ヒントは無効になります。 ORDERED ヒントを使用すると、OUTLINE DATAには ORDERED ヒントが表示されず、代わりに完全な LEADING ヒントが出力されます。
構文
/*+ ORDERED */
例
3つのテーブル employees、departments、job_history を結合する必要があると仮定します:
SELECT /*+ ORDERED */ e.employee_id, d.department_name, j.job_id
FROM employees e, departments d, job_history j
WHERE e.department_id = d.department_id
AND e.hire_date = j.start_date;
この例では、データベースは employees、departments、job_history の順序でこれら3つのテーブルを結合します。