DBAtlas · データベース運用アトラス

クエリの実行計画が劣化した (突然遅くなった)

昨日は高速だったクエリが、今日は突然遅くなった。通常はオプティマイザがより悪い実行計画に切り替わっている。古い統計情報、パラメータ依存性、データ量の増加、突然の実行計画の変更の中から根本原因を見つけ、実行計画を安定させる。

実行計画は本当に変わったのか、それはいつか?

同じクエリに複数の実行計画 (plan_hash/plan_generation) があるか、また低速化はいつ始まったか? 直近のデプロイ、アップグレード、パラメータ変更、大規模なデータロードと時期が一致するか?

SELECT sql_id, plan_hash_value, executions, ROUND(elapsed_time/GREATEST(executions,1)/1e6,3) AS sec_per_exec, first_load_time
FROM v$sql WHERE sql_id='&sqlid' ORDER BY first_load_time;
  • 統計情報が古い可能性がある
  • 同じクエリがパラメータによって異なる動作をする (sniffing/peeking)
  • データ量が大幅に増加した
  • アップグレード/フラッシュ後に実行計画が突然変わった

統計情報は最新か?

オプティマイザは統計情報に基づいて判断する。最後の analyze の日付が古い場合や変更カウンタが高い場合、推定値が実際にずれている可能性があり、それが不適切な実行計画につながる。

SELECT table_name, num_rows, last_analyzed, stale_stats
FROM dba_tab_statistics WHERE table_name='T';
  • 統計情報が古い/欠落している
  • 統計情報は最新だが、実行計画が依然としてパラメータに依存している

パラメータ依存性はあるか?

クエリは初回実行時のパラメータ値に基づいて実行計画を選択し、キャッシュする (MSSQL parameter sniffing / Oracle bind peeking)。その実行計画は、偏った分布を持つ他の値に対しては不適切な場合がある。

SELECT sql_id, child_number, plan_hash_value, is_bind_sensitive, is_bind_aware
FROM v$sql WHERE sql_id='&sqlid';
  • はい、パラメータによって実行計画が良し悪しの間で入れ替わる
  • 適切な実行計画は分かっている。恒久的に固定したい

根本原因: 古い / 欠落した統計情報

実態と一致しない古い統計情報に基づき、オプティマイザが行数を誤って推定し、不適切な実行計画を選択した。実行計画の劣化の最も一般的な原因。

根本原因: パラメータ依存性 (sniffing / bind peeking)

キャッシュされた実行計画は最初に到着したパラメータ値に合わせて選択されており、偏った分布を持つ他の値には不適切。目的は、値に適した実行計画が選択されるようにすること。

解決策: 適切な実行計画を固定する (baseline / force plan)

既知の良い実行計画がある場合、オプティマイザがそれから外れないよう固定すれば、劣化を恒久的に止められる。

根本原因: データ量が増加し、実行計画が合わなくなった

テーブルの増大に伴い、以前は理想的だった実行計画 (例: nested loop) がうまくスケールしなくなっている。オプティマイザには、増加を正しく反映した統計情報とアクセスパスが必要。

根本原因: 実行計画の突然の変更 (アップグレード / キャッシュのフラッシュ)

バージョンアップグレード、パラメータ変更、またはプランキャッシュのクリア後に実行計画が突然変わった。オプティマイザの動作または環境条件が変化している。

DBAtlas で開く →