AWRのSQL_IDに慣れていると、STATSPACKのHash Valueだけを頼りに実行計画へドリルダウンする手順には戸惑うはずです。重いSQLを特定してから実行計画にたどり着くまでの導線を、実際に何度もたどった手順そのままに書き起こしました。

SQL Statistics の全体像

チューニング対象SQL特定(STATSPACK)図

図1: STATSPACKでのSQLチューニング対象特定

STATSPACKの SQL Statistics は、AWRと同様に複数の観点でSQLをランキングしています。 ただし識別子が Hash Value(Old Hash Value) である点と、ランキング種類が若干異なる点に注意が必要です。

テーブル名ランキング基準適した問題
SQL ordered by CPU合計CPU消費時間CPU高負荷の原因SQL
SQL ordered by Elapsed Time合計経過時間全体的に最も重いSQL(最重要)
SQL ordered by Gets論理読み込みブロック数バッファキャッシュを大量消費するSQL
SQL ordered by Reads物理読み込みブロック数I/Oを引き起こすSQL
SQL ordered by Executions実行回数頻繁に呼ばれる軽いSQL(積み重ね)
SQL ordered by Parse Callsパース回数バインド変数未使用SQL

SQL Statisticsの各列定義は PART 05 — SQL Statistics 詳細(定義書) を参照。

Elapsed Time で重いSQLを特定する

まず SQL ordered by Elapsed Time を確認します。 合計Elapsed Timeが最も大きいSQLが全体負荷に最も寄与しています。

列名意味注目ポイント
Elapsed Time (s)合計経過時間(秒)最も総合的な重さを示す
Executions実行回数高回数×軽い or 低回数×重いを区別
Elapsed Time / Execute1回あたりの経過時間1回が重いSQLを特定できる
% Total DB TimeDB Timeに占める割合30%超のSQLは最優先でチューニング

CPU / Gets / Reads から原因を分析する

状況原因の仮説次のアクション
CPU Time ≒ Elapsed TimeCPU使用が多い(ソート・ハッシュ結合)実行計画確認、インデックス追加検討
Reads が多い物理I/O + バッファキャッシュミスPART 06 I/O分析
Gets が多い(Readsは少ない)論理読み込みが多い(効率の悪いアクセス)実行計画の見直し
Elapsed ≫ CPUI/O待ちまたは競合待ちPART 04 Wait分析

Hash Value から実行計画へのドリルダウン

STATSPACKではSQL識別子として Hash Value(Old Hash Value) が使われます。 AWRのSQL_IDとは異なる点に注意してください。

💡 Hash ValueでSQL全文と実行計画を確認する

STATSPACKのレポートでは、Hash ValueはSQLテキストへの参照番号です。 レポートの末尾の SQL Text セクションで対応するSQL全文を確認できます(Snap Level 5以上が必要)。 実行計画は PLAN_TABLEV$SQL_PLAN で別途確認が必要です。

⚠️ Old Hash Value と New Hash Value

Oracle 10g以降では SQL_ID(新形式)と Hash Value(旧形式)が共存しています。 STATSPACKは従来の Old Hash Value を使います。AWRのSQL_IDと相互変換する場合は変換関数が必要です。

STATSPACKでのSQL特定ワークフロー

AWRと異なりOEMのGUIが使えないSTATSPACK環境では、レポート → Hash Value → SQL Textという手順での確認が基本になる。

手順操作確認ポイント
① Elapsed Timeランキングで候補を絞る spreport.sqlのSQL ordered by Elapsed Timeセクションを参照 上位5件に普段は現れないSQLがないか。Hash Valueをメモする
② SQL Textセクションで全文を確認 レポート末尾のSQL TextセクションでメモしたHash Valueを探す Level 5以上のスナップでないと全文が出ない。STATSPACK.SNAPのi_snap_levelを確認
③ 複数スナップで傾向を比較する 同じHash Valueを別スナップ間のレポートで確認 Elapsed Timeが特定時間帯だけ急増していないか。バッチ時間帯と重なっていないか
④ 実行計画をV$SQL_PLANで取得する PERFSTAT.STATS$SQL_PLANかV$SQL_PLANをHash Valueで検索 フルスキャン・大きなCardinality誤りがないか。AWRと異なり自動取得されないため手動確認が必要

優先順位付けの考え方

SQLチューニングの優先順位

% Total DB Time が高いSQL(全体負荷への寄与が大きい)
Elapsed / Execute が異常に高いSQL(1回が重い)
Parse Calls ≒ Executions のSQL(毎回ハードパース)
④ 実行回数が多く積み重なっているSQL

SQL特定でよくある誤り

SQL Statistics のランキングは視点ごとに異なる。単一ランキングだけで判断すると重要なSQLを見落とす。

誤り何が起きるか正しい読み方
「Elapsed Time」ランキング1位のSQLだけをチューニング対象にする実行回数の多い低コストSQLの累積が全体に与える影響を見落とすCPU / Reads / Executions の各ランキングも確認し、複数軸で上位に来るSQLを優先する
Parse Calls ≒ Executions のSQLを見落とす毎回ハードパースしているSQLが放置され、Shared Pool競合やCPU高騰の遠因になるExecutions に対して Parse Calls が高い割合のSQLを「バインド変数化」候補として抽出する
SQLテキストの省略(末尾の...)のまま最適化策を決めるWHERE句の全体像や結合条件が見えないまま対策を立てると、的外れな索引追加等が発生するSQL_IDを特定したらV$SQLTEXTやDBMS_XPLAN.DISPLAY_CURSORで完全なSQLと実行計画を取得してから判断する