Oracle 12c から導入された適応型クエリ最適化(Adaptive Query Optimization)は、オプティマイザが実行前だけでなく実行中・実行後にも計画を改善する仕組みです。
従来のオプティマイザは実行計画を実行前に固定していました。統計情報の見積もり誤差が大きい場合はネストループ vs ハッシュ結合の選択を誤るなど実行後に問題が判明することがありました。適応型最適化は実行中にカーディナリティ見積もりを実測値と比較して計画を動的に修正します。
- 適応プラン(Adaptive Plans)で実行中に結合方法を切り替える仕組み
- 統計フィードバック(Statistics Feedback)で次回実行の計画を改善する仕組み
- 動的サンプリング(Dynamic Statistics)で統計情報不足を補う方法
- OPTIMIZER_ADAPTIVE_PLANS / OPTIMIZER_ADAPTIVE_STATISTICS パラメータの使い方
- 実行計画で適応機能の使用を確認する方法(DBMS_XPLAN の Note 欄)
- 適応機能を無効にすべき場面とトラブルシューティング
適応型クエリ最適化の全体像
| 機能 | タイミング | 制御パラメータ |
|---|---|---|
| 適応プラン | 実行中(リアルタイム)に結合方法を切り替える | OPTIMIZER_ADAPTIVE_PLANS |
| 統計フィードバック | 実行後に見積もり誤差を記録→次回実行で利用 | OPTIMIZER_ADAPTIVE_STATISTICS |
| 動的サンプリング | 実行前に一部データをサンプリングして統計を補完 | OPTIMIZER_DYNAMIC_SAMPLING |
-- 適応型クエリ最適化関連パラメータをまとめて確認する SELECT name, value, description FROM V$PARAMETER WHERE name LIKE 'optimizer_adaptive%' OR name LIKE 'optimizer_dynamic%' ORDER BY name; -- 主要パラメータのデフォルト値(Oracle 12.2 以降) -- optimizer_adaptive_plans : TRUE(適応プランを有効) -- optimizer_adaptive_statistics : FALSE(統計フィードバック・動的統計は無効) -- optimizer_dynamic_sampling : 2(最小限のサンプリング)
適応プラン(Adaptive Plans)— 実行中に結合方法を切り替える
適応プランでは、オプティマイザが統計収集プロバイダー(Statistics Collector)を実行計画の途中に挿入します。実行中にカーディナリティの実測値がしきい値を超えたとき、残りの処理でNested Loop から Hash Join(またはその逆)に切り替えます。
-- GATHER_PLAN_STATISTICS ヒントを使って実測値を収集する
SELECT /*+ GATHER_PLAN_STATISTICS */
d.department_name,
COUNT(e.employee_id) AS emp_count
FROM departments d
JOIN employees e ON d.department_id = e.department_id
GROUP BY d.department_name
ORDER BY emp_count DESC;
-- 実行後に ALLSTATS LAST で適応プランを確認する
SELECT * FROM TABLE(
DBMS_XPLAN.DISPLAY_CURSOR(
sql_id => NULL, -- NULL = 直前の SQL
cursor_child_no => 0,
format => 'ALLSTATS LAST +ADAPTIVE' -- +ADAPTIVE で適応情報を表示
)
);
-- Note 欄に以下が表示される:
-- - this is an adaptive plan(適応プランが使用された)
-- - final plan was この plan(実際に使われた結合方法)
-- 実行計画内で "-" 行が非アクティブな分岐(使われなかった結合方法)を示す
+ADAPTIVE フォーマットを使うと、実行計画に非アクティブな分岐(ダッシュ “-” が先頭)が表示されます。例えば Nested Loop と Hash Join の両方が表示され、ダッシュ付きの方が「使われなかった代替プラン」です。Note 欄の “this is an adaptive plan” が適応プランの使用を示します。
統計フィードバック(Statistics Feedback)— 次回実行を改善する
統計フィードバック(旧: Cardinality Feedback)は、実行後に見積もりカーディナリティと実測カーディナリティの差異を SGA 内に記録します。次回同じ SQL を実行する際にこの情報をオプティマイザが参照して、より正確なプランを選択します。
デフォルトでは OPTIMIZER_ADAPTIVE_STATISTICS=FALSE のため、統計フィードバックは無効です。
-- 統計フィードバックを有効にする(セッションレベル)
ALTER SESSION SET optimizer_adaptive_statistics = TRUE;
-- 統計フィードバックが適用されたかどうかを V$SQL で確認する
SELECT sql_id, executions, is_reoptimizable,
SUBSTR(sql_text, 1, 80) AS sql_head
FROM V$SQL
WHERE is_reoptimizable = 'Y' -- 再最適化が必要と判断された SQL
ORDER BY executions DESC;
-- is_reoptimizable = Y → 次回実行時に統計フィードバックを使って再計画される
-- 実行計画の Note 欄で統計フィードバックを確認する
-- "statistics feedback used for this statement" と表示される
動的サンプリング(Dynamic Statistics)— 統計情報不足を補う
動的サンプリングは SQL の実行前に対象テーブルの一部(ブロック)を実際にサンプリングして統計情報を補完します。統計情報が古い・欠如しているテーブルに対して特に効果的です。
-- 現在の動的サンプリングレベルを確認する SHOW PARAMETER optimizer_dynamic_sampling; -- レベルの説明: -- 0: 動的サンプリングなし -- 1: 統計情報がないテーブルのみ(最小限) -- 2: デフォルト(統計がないか古い場合に基本サンプリング) -- 4: より積極的なサンプリング -- 11: 自動(Oracle 12.2以降 - OPTIMIZER_ADAPTIVE_STATISTICS=TRUE の場合に有効) -- セッションレベルで変更する(本番への影響を避けるため) ALTER SESSION SET optimizer_dynamic_sampling = 4; -- 特定の SQL だけ動的サンプリングを指定するヒント SELECT /*+ DYNAMIC_SAMPLING(e 4) */ employee_id, salary FROM employees e WHERE salary > 10000;
-- 実行計画の Note 欄を確認する EXPLAIN PLAN FOR SELECT COUNT(*) FROM employees WHERE hire_date < DATE '2000-01-01'; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(format => 'TYPICAL')); -- Note 欄に "dynamic statistics used: dynamic sampling (level=N)" と表示されれば -- 動的サンプリングが使用されている
適応機能を無効にする方法
適応型クエリ最適化が原因で実行計画が不安定になる場合や、パフォーマンス問題のトラブルシューティング時に機能を無効化することがあります。
-- 適応プランのみ無効化する ALTER SESSION SET optimizer_adaptive_plans = FALSE; -- 統計フィードバック・動的統計も含めてすべて無効化する ALTER SESSION SET optimizer_adaptive_statistics = FALSE; -- 特定 SQL のみ適応プランを無効化するヒント SELECT /*+ NO_ADAPTIVE_PLAN */ * FROM employees e JOIN departments d ON e.department_id = d.department_id; -- システム全体で適応プランを無効化する(本番適用前に十分検証すること) ALTER SYSTEM SET optimizer_adaptive_plans = FALSE SCOPE=BOTH; -- 無効化の影響を受ける固定プランを確認する -- V$SQL で is_resolved_adaptive_plan 列を確認する SELECT sql_id, is_resolved_adaptive_plan, SUBSTR(sql_text, 1, 80) FROM V$SQL WHERE is_resolved_adaptive_plan IS NOT NULL;
まとめ
- 適応プラン:実行中に Nested Loop ↔ Hash Join を動的切り替え。OPTIMIZER_ADAPTIVE_PLANS=TRUE でデフォルト有効
- 統計フィードバック:実行後の実測カーディナリティを次回実行に活用。OPTIMIZER_ADAPTIVE_STATISTICS=FALSE がデフォルト(無効)
- 動的サンプリング:統計不足を実行前サンプリングで補完。DYNAMIC_SAMPLING ヒントで SQL 単位に制御できる
- +ADAPTIVE フォーマット:DBMS_XPLAN.DISPLAY_CURSOR の format オプションで適応プランの使用を可視化できる
- 実行計画が頻繁に変動する場合は SPM(SQL Plan Baselines)で計画を固定することも検討する
実行計画の詳細分析は DBMS_XPLAN完全ガイドを参照してください。実行計画の固定は SQL Plan Management(SPM)完全ガイドを参照してください。統計情報の収集・管理は DBMS_STATS完全ガイドも参照してください。