ねら~ITエンジニア雑記

やきうのお兄ちゃんが綴るOracle Databaseメインのブログ

Oracle の ASH(Active Session History) から リテラルSQL を追跡してみる。

Oracle の ASH(Active Session History) から リテラルSQL を追跡してみます。

ASH にはアクティブなセッションの履歴情報、もう少し詳しく言うと
DB CPU または 待機状態(Disk IO/ロック待ち/Network待機/etc...) の
セッション情報 が 1回/1秒 の間隔で自動サンプリングされて、
V$ACTIVE_SESSION_HISTORYビューに格納されます。下記も参照

Oracle® Databaseリファレンス
11gリリース2 (11.2)
B56311-10
V$ACTIVE_SESSION_HISTORY
http://docs.oracle.com/cd/E16338_01/server.112/b56311/dynviews_1007.htm#I1030299
 > V$ACTIVE_SESSION_HISTORYは、データベース内のサンプリングされた
 > セッション・アクティビティを表示します。これには、1秒に1回取得される、
 > アクティブなデータベース・セッションのスナップショットが含まれます。
 > データベース・セッションは、CPU上にあった場合、またはIdle待機クラスに
 > 属していないイベントを待機していた場合に、アクティブであるとみなされます。
 > 待機クラスの詳細は、V$EVENT_NAMEビューを参照してください。

リテラルSQLの場合、SQL_ID が都度替わるのでそこからは追跡できないですが、
SQL意味的に同じ(例:特定表を抽出するSQLでWHERE句絞込条件の値だけリテラル、等)
場合は PLAN_HASH_VALUE が同じになる公算が高く、そこから追跡ができなくもないです。

検証してみるZe!(`・ω・)ゞ リテラルSQLを流してみます。

SET TIME ON;
SET TIMING ON;
DECLARE
  v_sql  VARCHAR2(1000);
  d_date DATE;
BEGIN
  FOR i IN 1..100000
  LOOP
    EXECUTE IMMEDIATE 'SELECT /* ' || TO_CHAR(i) || '*/ SYSDATE FROM MY_DUAL'
    INTO d_date;
  END LOOP;
END;
/

PL/SQL procedure successfully completed.

Elapsed: 00:00:54.06
11:55:29 SQL>

下記の SQL で ASHの一部 を csv形式 で抜きます。

11:57:13 SQL> !cat ash.sql
SET LINESIZE 32767;
SET PAGESIZE 0;
SET FEED OFF;
SET TRIMSPOOL ON;
SET TERMOUT OFF;
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY/MM/DD HH24:MI:SS';
ALTER SESSION SET NLS_TIMESTAMP_FORMAT='YYYY/MM/DD HH24:MI:SS';

spool ash.csv
PROMPT "Y","M","D","H","MI","S","MODULE","PROGRAM","SQL_ID","EVENT","PLAN_HASH_VALUE"
SELECT    '"' || TO_CHAR(SAMPLE_TIME, 'YYYY') || '",'
       || '"' || TO_CHAR(SAMPLE_TIME, 'MM')   || '",'
       || '"' || TO_CHAR(SAMPLE_TIME, 'DD')   || '",'
       || '"' || TO_CHAR(SAMPLE_TIME, 'HH24') || '",'
       || '"' || TO_CHAR(SAMPLE_TIME, 'MI')   || '",'
       || '"' || TO_CHAR(SAMPLE_TIME, 'SS')   || '",'
       || '"' || MODULE                       || '",'
       || '"' || PROGRAM                      || '",'
       || '"' || SQL_ID                       || '",'
       || '"' || EVENT                        || '",'
       || '"' || SQL_PLAN_HASH_VALUE          || '"'
  FROM V$ACTIVE_SESSION_HISTORY
 WHERE SAMPLE_TIME BETWEEN TO_TIMESTAMP('2015/07/13 11:54:35', 'YYYY/MM/DD HH24:MI:SS')
                       AND TO_TIMESTAMP('2015/07/13 11:55:30', 'YYYY/MM/DD HH24:MI:SS');
spool off;

抽出結果は下記となります。

11:57:18 SQL> @./ash.sql
11:57:24 SQL> !cat ash.csv
"Y","M","D","H","MI","S","MODULE","PROGRAM","SQL_ID","EVENT","PLAN_HASH_VALUE"
"2015","07","13","11","55","28","SQL*Plus","sqlplus@dbserv1 (TNS V1-V3)","3w6rsvwhpz4kv","","2036514324"
"2015","07","13","11","55","27","SQL*Plus","sqlplus@dbserv1 (TNS V1-V3)","gmbj758mq2q0w","","2036514324"
"2015","07","13","11","55","26","SQL*Plus","sqlplus@dbserv1 (TNS V1-V3)","axsar92qx6b5m","","2036514324"
"2015","07","13","11","55","25","","oracle@dbserv1 (CKPT)","","","0"
"2015","07","13","11","55","25","SQL*Plus","sqlplus@dbserv1 (TNS V1-V3)","367v7k8d9m8xn","","2036514324""2015","07","13","11","54","37","SQL*Plus","sqlplus@dbserv1 (TNS V1-V3)","40prdnduwzaj3","","2036514324"
"2015","07","13","11","54","36","SQL*Plus","sqlplus@dbserv1 (TNS V1-V3)","cah0q6gtc2j22","","2036514324"
"2015","07","13","11","54","35","SQL*Plus","sqlplus@dbserv1 (TNS V1-V3)","5u4u63gu2ymfh","","2036514324"

11:57:29 SQL>

既に結果が見えて無くもないですが、せっかく csv形式 で抜いたので、
Excel でグラフにしてみます。ピボットグラフでがちゃがちゃすると……

PLAN_HASH_VALUE = 2036514324 の SQL が大量に居てるのが解ったやで。
こいつを V$SQLビュー から抜いてみると、、、

SELECT SQL_ID, CHILD_NUMBER, PLAN_HASH_VALUE
  FROM V$SQL
 WHERE PLAN_HASH_VALUE = 2036514324
 ORDER BY SQL_ID, CHILD_NUMBER;

SQL_ID        CHILD_NUMBER PLAN_HASH_VALUE
------------- ------------ ---------------
001kubp3kaswg            0      2036514324
00782rn7j921b            0      2036514324
008wkpdf4pxbc            0      2036514324
00an211rtx0v3            0      2036514324
:
gzws7gppv5x29            0      2036514324
gzyc248pqjnbz            0      2036514324
gzytchrgrdmt2            0      2036514324

適当にサンプリングして XPLAN で 実行計画共々SQLを抜いてみると、、、

SET LINESIZE 300;
SET PAGESIZE 1000;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(sql_id => '00an211rtx0v3', format => 'ALL ALLSTATS LAST'));

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------
SQL_ID  00an211rtx0v3, child number 0
-------------------------------------
SELECT /* 95297*/ SYSDATE FROM MY_DUAL

Plan hash value: 2036514324

----------------------------------------------------------------------
| Id  | Operation         | Name    | E-Rows | Cost (%CPU)| E-Time   |
----------------------------------------------------------------------
|   0 | SELECT STATEMENT  |         |        |     3 (100)|          |
|   1 |  TABLE ACCESS FULL| MY_DUAL |      1 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------

やった、リテラルSQL を ASH から特定したやで!(`・ω・)Ъ ※マッチポンプとも言う。

なお ASH参照には有償オプションが必要なんで、そこは注意しませふ(´・ω・)ゞ

Oracle® Databaseライセンス情報
11gリリース2 (11.2)
B56284-10
Oracle Diagnostics Pack
http://docs.oracle.com/cd/E16338_01/license.112/b56284/options.htm#CIHIHDDJ
 > V$ACTIVE_SESSION_HISTORY動的パフォーマンス・ビューおよびその基礎となる表X$ASHは、Diagnostics Packのライセンスが必要です。