RM-BLOG

IT系技術職のおっさんがIT技術とかライブとか日常とか雑多に語るブログです。* 本ブログに書かれている内容は個人の意見・感想であり、特定の組織に属するものではありません。/All opinions are my own.*

【ORACLE】セッションが実行中のSQLを調べる

ここに挙げたやり方に則り
実際によく使ってる簡易的にセッションの情報を取得するSQL。
リンク先で挙げたようなV$SESSIONとV$SESSION_LONGOPSに加えて
V$SQLを結合してSQL_FULLTEXTを取得します
(そのセッションがどんなSQL投げてるのか調べる)。


 

 

V$SQLの結合はSQLにもあるように
 
 and a.SQL_ADDRESS = c.ADDRESS(+)
 and a.SQL_HASH_VALUE = c.HASH_VALUE(+)
 and a.SQL_ID = c.SQL_ID(+)
 and a.SQL_CHILD_NUMBER = c.CHILD_NUMBER(+)
 
の部分で実現していますが、
例のごとくこれは経験則によるものなので
Oracleの仕様的にこれで一意になるのかわかりませんし、
実際一意にならなかった記憶が確かあります。
8~9割方はこれでほしい情報を取れるので
別にいいやってことで無理やり自分を納得させてますが、
一意になるつなげ方知ってたら教えてください。
手っ取り早く一意にするのはDISTINCTかけることですね。



V$SQL.SQL_FULLTEXTはCLOB型なので、
ツールによっては対応してない場合もあるかもしれません。
そういう場合は取得する項目を
V$SQL.SQL_TEXTに変更するほうがよいでしょう。
ただV$SQL.SQL_TEXTはVARCHAR(1000)なので
1000文字を超える長いSQLは途中で切れてしまいます。



SQL文が格納されているオブジェクトには他にV$SQLTEXTってのがありますが、
これはV$SQL.SQL_FULLTEXTのように1つのカラムに全SQLが載っているのではなく
SQL文がいい感じのところ(多分64文字)で別のレコードにそれぞれ分割されて
その状態でSQL文が格納されています。
⇒それぞれの行は
 V$SQLTEXT.PIECEというカラムで区別されています。(0から採番)
 いわゆる「行番号」ですね。
よって何も考えずにV$SQLTEXTを結合すると
1セッションで重複したレコードが大量に抽出されてしまいます。
逆に言うとPIECE=0に限定して結合すると「最初の1行」だけを取得できるので
「とりあえずどんなSQL投げてるのかちょっとだけ見たい」というケースでは使えます。
 
 SELECT S.SID,S.SERIAL#,T.SQL_TEXT
 FROM V$SESSION S
   ,(SELECT ADDRESS,HASH_VALUE,SQL_ID,SQL_TEXT
    FROM V$SQLTEXT
    WHERE PIECE=0
   ) T
 WHERE S.SQL_ADDRESS = T.ADDRESS(+)
  AND S.SQL_HASH_VALUE = T.HASH_VALUE(+)
  AND S.SQL_ID = T.SQL_ID(+)
 
こんな感じですかね。
V$SQLTEXT.SQL_TEXTはVARCHAR2(64)なので
SQL文の最初の64文字分は取得できるということになります。



なお、V$SQLもV$SQLTEXTも
全てのセッションに対応して存在してるわけではないので、
V$SESSION基準で結合する場合は外部結合にしないと必要なものしか取れません。