V$SQL_PLANでCRUD表モドキを作ってみる①

パフォーマンス問題の犯人探し?

情報システムに問題(特にパフォーマンス問題)が発生した場合、運用を担っているインフラ・チームが真っ先にやり玉に挙げられることが多いようです。

そんな時のアプリ・チームの主張は

  • 自分たちはアプリケーションに一切手を加えていないので悪くない。悪いはずがない。
  • インフラ・チームが何かやらかしたのではないか?(過去に痛い経験があればなおさら)
  • 隠しパラメータみたいな秘密のスイッチがあるらしいから、それをうまく使って切り抜けてくれ!
  • インフラには高い金をつぎ込んでいるのだから何とかしろ!

というようなものが多いのではないでしょうか?

しかも、大抵の場合アプリ・チームの方が人数が多いので、多勢に無勢いつの間にか問題はインフラ・チームのせいになってしまっている、というようなことはよくあります。

最近は、新卒でインフラ・チームに配属されるというケースも多くなっていますが、ベテラン開発者から運用者に転向しているような技術者は総じてスキルのレベルが高いので(好意的に解釈して)重要な問題の解決を期待されているということの裏返しなのかもしれません。

ただし、インフラ・チームの名誉のために補足しますが、私はパフォーマンス問題の8〜9割近くはSQLつまりアプリケーションの問題のような印象を持っています。(なぜアプリケーションに手を加えていないのに問題が発生するのかは改めて触れたいと思います。)

DBAは問題解決の要

DBAは多くの場合インフラ・チームの一員として数えられていますが、データベースはミドルウェアと言いながらOSから見れば一種のアプリケーションであるので、DBAがアプリ・チームとの仲介役としてうまく機能できれば問題解決に対して非常に強い組織になります。

専任のDBAを置いている組織は少ないかもしれません。サーバ管理者が兼任していたりしてDBAの職務が曖昧になっている場合、インフラ・チームとアプリ・チームの溝が深くなってしまうことはよくあります。

DBA自らがアプリケーションを理解する

問題が発生してからアクションを起こすのでは遅すぎます。DBAは常日頃からアプリケーションに対して関心を持つ必要があります。理想的にはアプリ・チームの責任としてDBAが理解できるドキュメントを整備するのがベストですが、現実的にはなかなか難しいことが多いかと思います。

従って、DBA側から能動的に情報を収集することが必要です。DBAから見た最も身近なアプリケーションはSQL文です。Oracleでは実行されているSQL文に関するさまざまな情報をV$SQL*ビュー(Oracle11gR2であれば30種)から得ることができます。

V$SQL_PLAN

それではV$SQL_PLANを使用してSQL文とテーブルの相関表を作ってみましょう。あるSQL文がどのテーブルを使用しているか、あるいはあるテーブルはどのようなSQL文によって使用されているかを一覧にしたものです。これはDB設計におけるCRUD表に近いものですが、実際に動いているSQL文の情報を使って作るというのがポイントです。

 実行計画のおさらい(SELECT)

以下の簡単な実行計画の例で考えてみます。

-----------------------------------------------------------------------------------
| Id  | Operation                     |  Name        | Rows  | Bytes | Cost (%CPU)|
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |              |     3 |   189 |    10  (10)|
|   1 |  NESTED LOOPS                 |              |     3 |   189 |    10  (10)|
|   2 |   NESTED LOOPS                |              |     3 |   141 |     7  (15)|
|*  3 |    TABLE ACCESS FULL          | EMPLOYEES    |     3 |    60 |     4  (25)|
|   4 |    TABLE ACCESS BY INDEX ROWID| JOBS         |    19 |   513 |     2  (50)|
|*  5 |     INDEX UNIQUE SCAN         | JOB_ID_PK    |     1 |       |            |
|   6 |   TABLE ACCESS BY INDEX ROWID | DEPARTMENTS  |    27 |   432 |     2  (50)|
|*  7 |    INDEX UNIQUE SCAN          | DEPT_ID_PK   |     1 |       |            |
-----------------------------------------------------------------------------------

まず中程の「Name」列は、その実行計画でアクセス(SELECT)されるテーブルあるいはインデックスとなります。テーブルなのかインデックスなのか名前から判断することもできますが確実なのは左隣りの「Operation」列が

  • TABLE ACCESS  で始まっているものが「テーブル」
  • INDEX で始まっているものが「インデックス」

です。

V$SQL_PLANからSELECT対象のテーブル一覧を取得する

V$SQL_PLANから情報を取得するクエリーを考えてみます。

select distinct
 SQL_ID
,OBJECT_NAME
,3 CRUD_TYPE_ID
,OPTIONS
from
 V$SQL_PLAN
where OPERATION like 'TABLE%'
and   OBJECT_OWNER = 'xxxx'
order by
 OBJECT_NAME
,CRUD_TYPE_ID
,SQL_ID;

8行目のWHERE条件でテーブルアクセスのオペレーションのみを取り出しています。
9行目ではテーブルの所有者で絞り込みをしています。

4行目で何をしているのかというと、V$SQL_PLANにはない V$SQL.COMMAND_TYPE に相当する情報をここで付加しています。
SELECTであれば「3」になります。この理由は追って説明します。

以下は実行例です。

SQL> select distinct
  2   SQL_ID
  3  ,OBJECT_NAME
  4  ,3 CRUD_TYPE_ID
  5  ,OPTIONS
  6  from
  7   V$SQL_PLAN
  8  where OPERATION like 'TABLE%'
  9  and   OBJECT_OWNER = 'SCOTT'
 10  order by
 11   OBJECT_NAME
 12  ,CRUD_TYPE_ID
 13  ,SQL_ID;

SQL_ID        OBJECT_NAME  CRUD_TYPE_ID OPTIONS
------------- ------------ ------------ --------
0cc0hqvr7kpgx BONUS                   3 FULL
30hdyzpfrzgbf BONUS                   3 FULL
3154rqzb8xudy DEPT                    3 FULL
678kpdu03jc8x DEPT                    3 FULL
1srhq04p4x0zz EMP                     3 FULL
a2dk8bdn0ujx7 EMP                     3 FULL
25tuw6725a9h7 SALGRADE                3 FULL
30p00zk91247c SALGRADE                3 FULL

8行が選択されました。

(続く)