Elapsed Timeで上位のSQLとCPU Timeで上位のSQLが一致せず、どちらを優先すべきか判断がつかなかったことがあります。SQL_IDの追い方を一から見直したときの視点をここに残します。

SQL Statisticsセクションには複数のランキングが並びます。それぞれが異なる観点でSQLをランク付けしているため、状況に応じて見るべきランキングが変わります。

Top 5 Timed Events で問題の方向性(CPU過多・I/O過多・ロック競合など)を把握した後、そのボトルネックに対応するランキングを見ることが重要です。やみくもに全ランキングを読むのではなく、仮説を持ってここに来るのが効率的です。

Elapsed Time Top 10

SQL Statistics分析図

図1: SQL StatisticsセクションのTop SQL特定フロー

総実行時間が長いSQL。長時間実行されている処理を特定するときに見ます。

代表的なパターン

  • SELECT * FROM 大きなテーブル ...
  • 複雑な結合クエリ
  • バッチ系の重いSQL

Elapsed Time Top 10 では、同じSQLでも実行回数(EXECUTIONS)と1回あたりの実行時間(Elapsed Time per Exec)を合わせて確認することが重要です。「1回あたりは速いが頻繁に実行されるSQL」と「1回あたりが遅いSQL」では対処法が異なります。前者はキャッシュや実行制御、後者は実行計画の改善が有効です。

着目ポイント: SQL_ID をコピーして実行計画(EXPLAIN PLAN)を確認する。

CPU Time Top 10

CPU消費量が多いSQL。解析・ソートが多い処理を特定するときに見ます。

代表的なパターン

  • GROUP BY / ORDER BY
  • 複雑な計算ロジック
  • 関数を多用したWHERE句

CPU Time が高いSQLのもう一つの原因がハードパースです。バインド変数を使わずにリテラル値(例:WHERE id = 123)を直接埋め込んだSQLは、実行のたびに異なるSQL文として扱われ、その都度新しい実行計画を生成するため、CPUを消費します。CPU Time Top 10 に似た形のSQLが複数登場している場合はバインド変数化を検討してください。

着目ポイント: ハードパース・解析過多の場合はバインド変数の使用を検討する。

Physical Reads Top 10

物理ディスク読み込みが多いSQL。インデックス未使用・フルスキャンを特定するときに見ます。

代表的なパターン

  • Full Table Scan クエリ
  • インデックス未使用クエリ
  • 巨大データのスキャン

Physical Reads が多い場合、Buffer Cache にデータがキャッシュされておらず、ディスクから読み直しているケースが大半です。インデックスを追加するか、クエリの条件を絞り込むことで Physical Reads を削減できる場合があります。一方で、バッチ処理など「大量のデータを一度だけ読む」ケースでは Physical Reads が多くなることは正常であり、むしろ Buffer Cache を温存するために RESULT_CACHE や並列読み取りを使うアプローチが有効です。

着目ポイント: EXECUTIONS(実行回数)も合わせて確認。
少ない実行回数で読み込み量が多い = 危険な兆候。

その他のランキング

SQL Statistics には上記3つ以外にも次のランキングがあります。状況に応じて参照してください。

ランキング 着目する状況
Gets (Buffer Gets) Top 10論理読み込みが多い = キャッシュは効いているが読み込み量が多すぎる
Executions Top 10非常に頻繁に実行されるSQLの特定。小さくても積み重なって負荷になる
Parse Calls Top 10ハードパース多発の特定。バインド変数化の優先度が高いSQLを見つける
Sharable Memory Top 10Shared Pool を大量消費するSQL。Shared Poolが枯渇気味な場合に確認

SQL_IDの活用

各ランキングには SQL_ID(Oracle がSQLを一意に識別する文字列)が付随しています。これをコピーして以下のような調査に活用します。

  • V$SQL / DBA_HIST_SQLTEXT でSQL本文を確認
  • DBMS_XPLAN で実行計画を確認
  • SQLチューニングアドバイザに投入
AWRレポートをHTML形式で生成している場合、SQL_IDはレポート内のリンクになっており、クリックでSQL本文や実行計画にジャンプできます。

SQL本文の確認は次のクエリで行えます。

-- SQL_IDからSQL本文を取得(実行中のSQLから)
SELECT sql_id, sql_text
FROM   v$sql
WHERE  sql_id = '&sql_id';

-- AWR履歴(過去のSQL)から取得
SELECT sql_id, sql_text
FROM   dba_hist_sqltext
WHERE  sql_id = '&sql_id';

実行計画を確認するときは DBMS_XPLAN.DISPLAY_AWR を使うと、AWRに記録された過去の実行計画を参照できます。現在と過去の実行計画を比較することで、性能劣化が実行計画の変化によるものかどうかを判断できます。

-- AWRに保存された実行計画を表示
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('&sql_id'));

SQL Statistics読み方でよくある誤り

誤り何が起きるか正しい対処
Elapsed Time Top 10だけ見て対象SQLを決める 実行回数が非常に多い低コストSQLが積み重なって全体負荷になっているケースを見落とす Executions Top 10もあわせて確認し、「頻度 × 単体コスト」でトータル負荷を評価する
SQLチューニング後にAWRで再確認しない チューニング済みSQLのSQL_IDが変わり、改善効果が正しく測れないことがある チューニング前後のAWRレポートを比較(awrddrpt.sql)してSQL別の変化を数値確認する
Parse Calls Top 10を見落とす バインド変数未使用でハードパースが連続するSQLはElapsed時間が短くても共有プールを圧迫する Parse Calls が多いSQLはバインド変数化を最優先に検討する