共有プール領域に関する検証 その2

<共有プールに関する検証 その2> ペンネーム ダーリン

– V$SQLAREA と 負荷の高いSQL --

今週も、先週に続いて共有プールを覗いていこう。

先週は、動的パフォーマンスビューのV$SQLAREA表を使って類似SQL文を見つけ
る方法と、CURSOR_SHARINGを設定して、バインド変数の利用と同等の効果を実
現する方法を紹介した。

さて、今回はそのV$SQLAREA表から負荷の高いSQLを見つけてみよう。

V$SQLAREA表には、SQLの負荷を見極めるために有効な情報として以下のような
統計データがある。

===  ===

SHARABLE_MEM
EXECUTIONS
LOADS
FIRST_LOAD_TIME
PARSE_CALLS
DISK_READS
BUFFER_GETS
ROWS_PROCESSED
ADDRESS
HASH_VALUE

上記のカラムはいずれも重要な情報であるが、負荷が高いかどうかを見極め
るためには、”DISK_READS”と、”BUFFER_GETS”の値が重要な意味を持つ。

“DISK_READS”は文字通り、そのSQLが取得したデータの内、ディスクから取得
したデータ量(Oracle BLOCKS)をあらわしている。
当めるまがでもたびたび登場するが、ディスクからのデータ取得はメモリか
らの取得と比較してかなり時間が掛かる。よってこの値が大きいSQLが負荷の
高いSQLの第一候補となる。

ところが昨今のシステムでは、ディスクからのデータ読み込みが発生してい
ないのに(”DISK_READS”の値はさほど大きくないのに)レスポンスが悪いな
どという珍(?)現象が起こっている。でも、ディスク読み込みが発生して
いないからSQLには問題ないように見える。このような環境では、おそらく巨
大に設定したデータベースバッファ上にほとんどのデータを載せていること
が予想されるが、「なんだ理想的な状態じゃないか。」とは思わないでほし
い。

メモリ上で処理が完結すること自体は問題ないが、このメモリ上で、全件検
索のSQL文が乱発されている場合は大いに問題である。いくらハードウェアの
性能が向上したからといっても、これではきりがない。
また、これらはディスクからのデータ読み込みを引き起こす予備軍でもある。
データ件数が変われば、とたんに物理読み込みを引き起こすSQLに変貌する。

“DISK_READS”が発生しているSQLはまさしく「氷山の一角に過ぎない」のであ
る。

言い換えれば、SQL文自体の負荷を見極めるためには、実は”DISK_READS”より
も”BUFFER_GETS”が重要であるということだ。。

いずれにしても、以下のSQL文を参考にしてそれぞれの値が大きいSQL文を特
定してみよう。

負荷の高いSQL文を確認するSQL文?(DISK_READSが大きいSQL文の取得)

  1  select sql_text
  2        ,executions
  3        ,disk_reads
  4        ,buffer_gets
  5  from v$sqlarea
  6  where decode(executions ,0,disk_reads,disk_reads/executions)
  7         > (select avg(decode(executions,0,disk_reads
  8                                        ,disk_reads/executions))
  9                   + stddev(decode(executions,0,disk_reads
 10                                        ,disk_reads/executions))
 11            from v$sqlarea)
 12* and parsing_user_id != 0
SQL> /

SQL_TEXT
---------------------------------------------------------------------
EXECUTIONS DISK_READS BUFFER_GETS
---------- ---------- -----------
select EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO from scott
.t_emp where EMPNO = 7900
         8        868        6973

負荷の高いSQL文を確認するSQL文?(BUFFER_GETSが大きいSQL文の取得)

  1  select sql_text
  2        ,executions
  3        ,disk_reads
  4        ,buffer_gets
  5  from v$sqlarea
  6  where decode(executions ,0,buffer_gets,buffer_gets/executions)
  7         > (select avg(decode(executions,0,buffer_gets
  8                                        ,buffer_gets/executions))
  9                   + stddev(decode(executions,0,buffer_gets
 10                                             ,buffer_gets/executions))
 11            from v$sqlarea)
 12* and parsing_user_id != 0
SQL> /

SQL_TEXT
--------------------------------------------------------------------
EXECUTIONS DISK_READS BUFFER_GETS
---------- ---------- -----------
BEGIN DBMS_OUTPUT.DISABLE; END;
         2          0         608

select EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO from scott
.t_emp where EMPNO = 7900
         8        868        6973

上記のSQL文を実行すると、1SQL実行あたりのDISK_READSまたはBUFFER_GETS
が共有プールに存在するSQL全体の[平均値]+[標準偏差]を超えるSQL文を取得
することが出来る。

ここで取得されたSQL文について全件検索を行っていないかどうか、実行計画
を取得して見ることをお勧めする。

上記では”1実行あたりの負荷が高い”という観点で「負荷の高いSQL文」を取
得した。もうひとつ、注意していただきたい点がある。”1実行あたりの負荷”
はそれほど高くはないが、実行回数が極めて多いSQLである。

最近多いWEBシステムのバックで稼動するデータベースの場合は、このケース
で負荷が掛かることが多いのではないだろうか。
これに該当するようなSQLを取得する場合は”EXECUTIONS”と”BUFFER_GETS”の
値が大きいSQLを取得すればよいだろう。

ただし、WEB系のシステムで稼動するデータベースの場合、接続数などSQL文
以外の問題が潜んでいる場合も多い。

今回、メモリ上にデータが載っていても全件検索が行われているようだと問
題だということを述べた。そこで次回は、全件検索が問題となる一例を
V$LATCH表から見てみよう。

以上 ボディーボーダーいっぱいの茅ヶ崎にて