パフォーマンスがころころ変化するSQLの調査

これもよくありますよね。
速かったり、遅かったりするけど、原因がなぜかわからない・・・。
こういう場合、実行計画がころころ変化してるケースが非常に多いです。
ということで、それの調べ方を。
あ、10gの話になるので、9i以前の方はすみません。




ここでは、例として下記のSQLのパフォーマンスがころころ変わっているとします。
このSQLOracle内部で発行されているSQLなのですが、
ユーザが発行してるものだと思ってください。

select procedure#,procedurename,properties,itypeobj#
 from procedureinfo$ where obj#=:1 order by procedurename desc, overload# desc


9iまでは、こういったSQLレベルでの実行計画の変化を確認する場合、
Statspack の Snapshot を Level 6 以上で取得しておく必要がありましたが、
10g では、デフォルトで Automatic Workload Repository(以下AWR)という機能が動いており、
なにもしなくても、こういった情報を蓄積してくれています。


ただし!
この機能に付随するテーブルやビューへのアクセス、
パッケージの使用に関しては、Diagnostics Pack のライセンスが必要となるようです。
以下のSQLもライセンスが無いと実行してはいけないと思われます。
詳しくはこちら。
http://www.oracle.co.jp/products/price/oem10g_function.html
もしくは、OracleDirectまで。


はい、気を取り直して調査開始しましょう。
まずは、このSQLSQL_IDを確認する必要があります。
V$SQLあたりを引っ掛ければOKですね。

SQL> SELECT SQL_ID FROM V$SQL WHERE SQL_TEXT LIKE 'select
procedure#,procedurename,properties,itypeobj# from procedureinfo$
where obj#=:1 order by procedurename desc, overload# desc%';

SQL_ID
--------------------
dcstr36r0vz0d
dcstr36r0vz0d


2行出てますが、おそらく複数回パースがされているのでしょう・・・。
気にせず次いきます。
ここで、取得したSQL_IDを元に、AWRで持っている情報を引っ掛けにいきます。
たびたび出てきている DBMS_XPLAN というパッケージのDISPLAY_AWR というプロシージャで
AWR内部で持っている該当のSQLの実行計画を確認することが可能なんです。

SQL> select * from table(DBMS_XPLAN.DISPLAY_AWR('dcstr36r0vz0d',null,null,'ALL'));

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
SQL_ID dcstr36r0vz0d
--------------------
select procedure#,procedurename,properties,itypeobj# from
procedureinfo$ where obj#=:1 order by procedurename desc, overload# desc

Plan hash value: 17720163

----------------------------------------------------------------------
| Id  | Operation                    | Name             | Cost (%CPU)|
----------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                  |            |
|   1 |  SORT ORDER BY               |                  |     0   (0)|
|   2 |   TABLE ACCESS BY INDEX ROWID| PROCEDUREINFO$   |            |
|   3 |    INDEX RANGE SCAN          | I_PROCEDUREINFO1 |            |
----------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

  1 - SEL$1
  2 - SEL$1 / PROCEDUREINFO$@SEL$1
  3 - SEL$1 / PROCEDUREINFO$@SEL$1

SQL_ID dcstr36r0vz0d
--------------------
select procedure#,procedurename,properties,itypeobj# from
procedureinfo$ where obj#=:1
order by procedurename desc, overload# desc

Plan hash value: 3798950322

-------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                  |       |       |     5 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID | PROCEDUREINFO$   |    28 |   868 |     5   (0)| 00:00:01 |
|   2 |   INDEX RANGE SCAN DESCENDING| I_PROCEDUREINFO1 |    28 |       |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

  1 - SEL$1 / PROCEDUREINFO$@SEL$1
  2 - SEL$1 / PROCEDUREINFO$@SEL$1


44行が選択されました。


2種類出てきました。
でも、これだけだと、どっちが速くてどっちが遅いかは判断がつきにくい場合があります。
そこで、どの時間帯にどちらの実行計画が使用されていたかを確認し、
実際の使用感から、どっちの実行計画が優れているのかを判断します。


下記のSQLを実行することによって、時間帯ごとの実行計画の変化が確認できます。

SQL> set linesize 120
SQL> set pagesize 1000
SQL> col BEGIN_INTERVAL_TIME for a30
SQL> col SQL_ID for a20
SQL> SELECT DISTINCT
 2         SQL.SNAP_ID ,SNAP.BEGIN_INTERVAL_TIME
 3        ,SQL.SQL_ID ,SQL.PLAN_HASH_VALUE
 4    FROM SYS.WRH$_SQLSTAT SQL
 5        ,SYS.WRM$_SNAPSHOT SNAP
 6   WHERE SQL.SNAP_ID = SNAP.SNAP_ID
 7     AND SQL.SQL_ID='dcstr36r0vz0d'
 8   ORDER BY SQL.SNAP_ID;

  SNAP_ID BEGIN_INTERVAL_TIME            SQL_ID               PLAN_HASH_VALUE
---------- ------------------------------ -------------------- ---------------
       37 08-05-20 18:55:53.000          dcstr36r0vz0d             3798950322
       38 08-05-22 13:42:05.000          dcstr36r0vz0d             3798950322
       40 08-05-22 15:00:18.037          dcstr36r0vz0d             3798950322
       41 08-05-22 16:00:21.243          dcstr36r0vz0d             3798950322
       42 08-05-25 14:42:14.000          dcstr36r0vz0d             3798950322
       43 08-05-25 14:53:20.252          dcstr36r0vz0d               17720163
       44 08-05-27 13:24:05.000          dcstr36r0vz0d               17720163


「PLAN_HASH_VALUE」列が実行計画の表示の「Plan hash value:」と対応しています。
上記の結果が返ってきていて、「08-05-25 14:42:14 ごろまでは速かった」という
証言が取れていれば、PLAN_HASH_VALUE:3798950322 のほうが速いということに
なりますので、ヒント句などを使用して、SQLの実行計画をそのように固めてあげればよいのです。


なお、今回の実験ですが、
一部説明しにくい結果が返ってきていたところがありましたので、
わかりやすいように改変しています。ご了承ください。


次回は、Diagnostics Pack のライセンス買ってねーよ!
って人のために、Statspackで同じような情報が
簡単に取り出せないか、実験してみたいと思います。


では。