7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Oracle DatabaseでSQLの性能計測3(SQLトレース編)【Oracle Database or GoldenGate Advent Calendar 2018 Day 20】

Last updated at Posted at 2018-12-21

このエントリは Oracle Database or GoldenGate Advent Calendar 2018 の Day 20 の
記事となります。一日遅れてしまいました。スミマセン彡(-)(-)

Oracle Database or GoldenGate Advent Calendar 2018
https://adventar.org/calendars/3525

今日は Oracle Database で SQLトレースを取得して、
SQLの実行時間を計測してみるやで彡(゚)(゚) Day 8 の続きになります。

Oracle DatabaseでSQLの性能計測2(DBMS_XPLAN&DBMS_SQLTUNE編)
【Oracle Database or GoldenGate Advent Calendar 2018 Day 8】
https://gonsuke777.hatenablog.com/entry/2018/12/08/215428

1. SQLトレースとは?

セッション内で実行される個々のSQLのパフォーマンス情報を取得する機能です。
この記事でも幾つか記述しますが、下記のような情報を採取する事が可能です。

Oracle Database SQLチューニング・ガイド 18c
23.1.3.1 SQLトレース機能の概要
https://docs.oracle.com/cd/E96517_01/tgsql/performing-application-tracing.html#GUID-374ABE48-C63F-4A7B-B80E-906A51F9246C
SQLトレースは、文ごとに次の統計を生成します。
・解析、実行、フェッチのカウント
・CPU時間および経過時間
・物理読取りおよび論理読取り
・処理された行数

2. SQLトレースの出力先と出力可能サイズの確認

下記マニュアルの手順通り、まずSQLトレースの出力先と出力可能サイズを確認します。

Oracle Database SQLチューニング・ガイド 18c
23.4.1 手順1: トレース・ファイル管理用の初期化パラメータの設定
https://docs.oracle.com/cd/E96517_01/tgsql/performing-application-tracing.html#GUID-A4FD1913-D35A-4EE6-9CE8-361718433E91

まず DIAGNOSTIC_DESTパラメータ のパスを確認します。

SHOW PARAMETER DIAG

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
diagnostic_dest                      string      /u01/app/oracle

上記の結果より、自動診断リポジトリ(ADR)ホーム の場所を確定します。

Oracle Database データベース・リファレンス 18c
1.100 DIAGNOSTIC_DEST
https://docs.oracle.com/cd/E96517_01/refrn/DIAGNOSTIC_DEST.html#GUID-BFE9648A-24D4-4717-8C33-21B0868401EE
:
DIAGNOSTIC_DESTによって指定されるディレクトリの構造は、次のとおりです。

<diagnostic_dest>/diag/rdbms/<dbname>/<instname>
:

ADRホーム・ディレクトリの下に配置されるファイルは、次のとおりです。

・トレース・ファイル - /traceサブディレクトリに配置されます。
:

今回の環境は Single(非RAC)環境 で DB名, インスタンス名, いずれも orclcdb となります。
トレースファイルは ADRホームのtrace配下に出力されるため、今回は下記のパスに出力されます。

# トレースファイルの出力先
/u01/app/oracle/diag/rdbms/orclcdb/orclcdb/trace

MAX_DUMP_FILE_SIZEパラメータも確認します。今回の環境は unlmited にセットされています。

SHOW PARAMETER MAX_DUMP

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
max_dump_file_size                   string      unlimited

3. DBMS_SESSIONパッケージでセッション単位でSQLトレースを取得

SQLトレースを取得するには幾つかの方法が有りますが、
今回は DBMS_SESSIONパッケージのSESSION_TRACE_ENABLEプロシージャで、
セッション単位でSQLトレースを取得します。10046?知らんなぁ?彡(゚)(゚)

Oracle Database PL/SQLパッケージおよびタイプ・リファレンス 18c
146 DBMS_SESSION
SESSION_TRACE_ENABLEプロシージャ
https://docs.oracle.com/cd/E96517_01/arpls/DBMS_SESSION.html#GUID-0EF8429F-B552-40D0-885C-3C560A66152D

トレースファイルを識別し易くするために、TRACEFILE_IDENTIFIERパラメータもセットします。

Oracle Databaseデータベース・リファレンス, 18c
1.336 TRACEFILE_IDENTIFIER
https://docs.oracle.com/cd/E96517_01/refrn/TRACEFILE_IDENTIFIER.html#GUID-976352B6-1189-4B73-835B-9D5441D11115

下記がSQLトレース取得の実行サンプルになります。TRACEFILE_IDENTIFIERパラメータを
セットしつつ、待機イベント/バインド変数/行ソース統計を全て取得します。

それぞれのパラメータ(waits, binds, plan_stat)の意味は、生トレースの章で解説します。

-- TRACEFILE_IDENTIFIERパラメータをセット
ALTER SESSION SET TRACEFILE_IDENTIFIER = "AYSHIBAT";

-- SQLトレースを有効化
EXEC DBMS_SESSION.SESSION_TRACE_ENABLE(waits => TRUE, binds => TRUE, plan_stat => 'ALL_EXECUTIONS');

-- サンプルSQL
SELECT /*+ MONITOR */
       B.ITEM_NAME
     , TRUNC(A.ORDER_DATE, 'DD') AS ORDER_DAILY
     , COUNT(*)
  FROM ORDER_TBL A
     , ITEM_TBL B
 WHERE A.ITEM_NO  = B.ITEM_NO
--   AND B.ITEM_NO BETWEEN 1 AND 100
   AND TO_CHAR(B.REGIST_DATE, 'YYYYMMDD') = '20120801'
 GROUP BY B.ITEM_NAME, TRUNC(A.ORDER_DATE, 'DD')
 ORDER BY 1;

-- SQLトレースを無効化
EXEC DBMS_SESSION.SESSION_TRACE_DISABLE;

Session altered.

PL/SQL procedure successfully completed.

261 rows selected.

PL/SQL procedure successfully completed.

4. 出力されたSQLトレースの確認と整形(tkprof)

  1. で確認したディレクトリに移動して、SQLトレースファイルを確認します。
cd /u01/app/oracle/diag/rdbms/orclcdb/orclcdb/trace
ls -ltra *AYSHIBAT*

[oracle@localhost trace]$
[oracle@localhost trace]$ cd /u01/app/oracle/diag/rdbms/orclcdb/orclcdb/trace
[oracle@localhost trace]$ ls -ltra *AYSHIBAT*
-rw-r-----. 1 oracle oinstall  123298 Dec 21 01:03 orclcdb_ora_26747_AYSHIBAT.trm
-rw-r-----. 1 oracle oinstall 1842101 Dec 21 01:03 orclcdb_ora_26747_AYSHIBAT.trc ★出力されたトレース
[oracle@localhost trace]$

出力されたトレースファイルをtkprofコマンドで整形します。
tkprofにも幾つかオプション(sys=no, aggregate=no, sortなど)が有るのですが、
今回はシンプルに出力ファイル名のみ指定しますやで彡(゚)(゚)

tkprof orclcdb_ora_26747_AYSHIBAT.trc orclcdb_ora_26747_AYSHIBAT.trc.txt
ls -ltra *AYSHIBAT*

TKPROF: Release 18.0.0.0.0 - Development on Fri Dec 21 01:29:27 2018

Copyright (c) 1982, 2018, Oracle and/or its affiliates.  All rights reserved.

-rw-r-----. 1 oracle oinstall  123298 Dec 21 01:03 orclcdb_ora_26747_AYSHIBAT.trm
-rw-r-----. 1 oracle oinstall 1842101 Dec 21 01:03 orclcdb_ora_26747_AYSHIBAT.trc
-rw-r--r--. 1 oracle oinstall   41833 Dec 21 01:29 orclcdb_ora_26747_AYSHIBAT.trc.txt ★整形されたトレース

5. 整形(tkprof)済みトレースの見方

5-1. 整形(tkprof)済みトレースの抜粋

整形(tkprof)済みトレースから、対象SQLの結果を抜粋します。

********************************************************************************
:
SELECT /*+ MONITOR */
       B.ITEM_NAME
     , TRUNC(A.ORDER_DATE, 'DD') AS ORDER_DAILY
     , COUNT(*)
  FROM ORDER_TBL A
     , ITEM_TBL B
 WHERE A.ITEM_NO  = B.ITEM_NO
--   AND B.ITEM_NO BETWEEN 1 AND 100
   AND TO_CHAR(B.REGIST_DATE, 'YYYYMMDD') = '20120801'
 GROUP BY B.ITEM_NAME, TRUNC(A.ORDER_DATE, 'DD')
 ORDER BY 1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.02       0.02          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch       19      3.21      13.70       6669       8926          0         261
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       21      3.23      13.73       6669       8926          0         261

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 129
Number of plan statistics captured: 1

Rows (1st) Rows (avg) Rows (max)  Row Source Operation
---------- ---------- ----------  ---------------------------------------------------
       261        261        261  SORT GROUP BY (cr=8926 pr=6669 pw=6669 time=13704807 us starts=1 cost=30 size=208 card=8)
     26000      26000      26000   HASH JOIN  (cr=8926 pr=6669 pw=6669 time=13880000 us starts=1 cost=29 size=676 card=26)
   2600000    2600000    2600000    TABLE ACCESS FULL ORDER_TBL (cr=8835 pr=0 pw=0 time=378587 us starts=1 cost=3 size=286 card=26)
        10         10         10    TABLE ACCESS FULL ITEM_TBL (cr=91 pr=0 pw=0 time=856 us starts=1 cost=26 size=4500 card=300)


Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                      19        0.00          0.00
  direct path write temp                       6669        0.00         11.31
  direct path read temp                        6669        0.00          0.06
  SQL*Net message from client                    19        3.38          3.48
********************************************************************************
:

5-2. 整形(tkprof)済みトレースの表形式統計の確認

下記の部分(表形式の統計)に着目します。

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.02       0.02          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch       19      3.21      13.70       6669       8926          0         261
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       21    3.23     13.73     6669     8926          0       261

対象のSQLについて、cpu時間で3.23秒、経過時間が13.73秒、diskアクセスが6669回、
一貫性読取で8926ブロック、フェッチ行数は261行であることが確認できます。

それぞれの統計の意味はマニュアルも参照して下さい。

Oracle Database SQLチューニング・ガイド 18c
23.6.2.5.2 TKPROFの表形式の統計
https://docs.oracle.com/cd/E96517_01/tgsql/performing-application-tracing.html#GUID-B6EE4109-5946-415D-9B75-EC1B73D16B87

整形(tkprof)済みSQLトレースの冒頭にも載ってますやね!彡(゚)(゚)

:
********************************************************************************
count    = number of times OCI procedure was executed
cpu      = cpu time in seconds executing
elapsed  = elapsed time in seconds executing
disk     = number of physical reads of buffers from disk
query    = number of buffers gotten for consistent read
current  = number of buffers gotten in current mode (usually for update)
rows     = number of rows processed by the fetch or execute call
********************************************************************************
:

5-3. 整形(tkprof)済みトレースの行ソース統計の確認

次は下記の部分(行ソース統計)に着目します。

Rows (1st) Rows (avg) Rows (max)  Row Source Operation
---------- ---------- ----------  ---------------------------------------------------
       261        261        261  SORT GROUP BY (cr=8926 pr=6669 pw=6669 time=13704807 us starts=1 cost=30 size=208 card=8)
     26000      26000      26000   HASH JOIN  (cr=8926 pr=6669 pw=6669 time=13880000 us starts=1 cost=29 size=676 card=26)
   2600000    2600000    2600000    TABLE ACCESS FULL ORDER_TBL (cr=8835 pr=0 pw=0 time=378587 us starts=1 cost=3 size=286 card=26)
        10         10         10    TABLE ACCESS FULL ITEM_TBL (cr=91 pr=0 pw=0 time=856 us starts=1 cost=26 size=4500 card=300)

まずは time値 に着目します。実行計画の各ステップで、
どの程度時間が掛かったかを表します。μ秒(1/1,000,000秒)表記です。

Row Source Operation
---------------------------------------------------
SORT GROUP BY                 time=13704807 us ★ここまでで13.70秒掛かっている。
 HASH JOIN                    time=13880000 us ★ここまでで13.88秒掛かっている。
  TABLE ACCESS FULL ORDER_TBL time=378587 us
  TABLE ACCESS FULL ITEM_TBL  time=856 us

上記例だと HASH JOIN までのステップで 13880000us(13.88秒)、
SORT GROUP BY までのステップで 13704807us(約13.7秒)掛かっています。
※矛盾が有りますが、傾向を掴む事が重要なので多少の誤差は(゚ε゚ )キニシナイ!

次に cr値、pr値、pw値に着目。cr値は一貫性読込のブロック数、
pr値は物理読込の回数、pw値は物理書込の回数を表します。

Row Source Operation
---------------------------------------------------
SORT GROUP BY                 cr=8926 pr=6669 pw=6669 
 HASH JOIN                    cr=8926 pr=6669 pw=6669 ★ここで6669回の物理読込/物理書込が発生
  TABLE ACCESS FULL ORDER_TBL cr=8835 pr=0    pw=0    ★ここまでで8835ブロックの一貫性読込が発生
  TABLE ACCESS FULL ITEM_TBL  cr=91   pr=0    pw=0

上記例だと TABLE ACCESS FULL ORDER_TBL のステップで 8835ブロックの一貫性読込が、
HASH JOIN のステップで 6669回の物理読込/物理書込が発生している事が確認できます。

その次はオプティマイザの予測値と実測値の確認。
cost がオプティマイザの予測コスト値、size が予測バイト数、card が予測行数になりますが、
その中の予測行数(card)と実測行数(Rows)を比較します。
DBMS_XPLAN や DBMS_SQLTUNE の時と同じ流れですやね彡(゚)(゚)

Rows (1st) Row Source Operation
---------- ---------------------------------------------------
       261 SORT GROUP BY                 card=8
     26000  HASH JOIN                    card=26
   2600000   TABLE ACCESS FULL ORDER_TBL card=26 ★実測値(2,600,000)と予測値(26)が乖離
        10   TABLE ACCESS FULL ITEM_TBL  card=300

上記例だと ORDER_TBL の実測行数(2,600,000行)と予測行数(26行)が乖離しているのが確認できます。

各行ソース統計の値の意味については、マニュアルも参照して下さい。

Oracle Database SQLチューニング・ガイド 18c
23.6.2.5.4 TKPROFの行ソースの操作
https://docs.oracle.com/cd/E96517_01/tgsql/performing-application-tracing.html#GUID-77906451-193D-4D73-BA49-95A64445C673

下記のドキュメントも確認ですやで彡(゚)(゚) ※要My Oracle Supportアカウント

TKProf Interpretation (9i and above) (ドキュメントID 760786.1)
https://support.oracle.com/epmos/faces/DocumentDisplay?id=760786.1

5-4. 整形(tkprof)済みトレースの待機イベントの確認

最後に下記の部分(待機イベント部分)に着目します。

Elapsed times include waiting on following events:
  Event waited on                   Times   Max. Wait  Total Waited
  ------------------------------   Waited  ----------  ------------
  SQL*Net message to client            19        0.00          0.00
  direct path write temp             6669        0.00         11.31 direct path write tempで時間が掛かっている。
  direct path read temp              6669        0.00          0.06
  SQL*Net message from client          19        3.38          3.48

以上の結果より、下記の事実が確認できます。

  • ORDER_TBL表の Rows(実測値) と card(予測値)が乖離している。
  • HASH JOINのステップで時間が掛かっている。
  • direct path write tempの待機イベントで時間が掛かっている。

このようなケースでは以下のようなチューニングを試すのがセオリーとなります。※前回のコピペ

  • オプティマイザ統計の採取
  • ヒストグラム、拡張統計(複数列統計, 式統計)の取得
  • SQLチューニング・アドバイザの実行 と SQLプロファイルの適用(※)
     ※SQLプロファイルが提案された場合

6. 整形(tkprof)前の生トレース確認

6-1. 整形(tkprof)前の生トレースで確認できる情報

整形前の生トレースを見ると、下記の情報も確認できます。

  • 待機イベントの(WAIT行)
  • バインド変数(BINDSセクション)
  • 行ソース統計(STAT行)
  • etc...

下記に生トレースに関する先端技様の良い記事もあります。是非ご参照を彡(^)(^)

整形する前の SQL トレースを見ることが有益なケース
http://www.intellilink.co.jp/article/column/ora-report20150507.html

6-2. WAIT行(待機イベント)を生トレースで確認

DBMS_SESSION.SESSION_TRACE_ENABLE の waits => TRUE は、
SQLトレースにWAIT行を出力するオプションとなります。

下記は生トレースのWAIT行サンプルです。

-- 生トレースのWAIT行サンプル

WAIT #140512706274008: nam='SQL*Net message to client' ela= 11 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=14331548081
WAIT #140512706274008: nam='direct path write temp' ela= 4310 file number=203 first dba=391 block cnt=1 obj#=-1 tim=14331638606
WAIT #140512706274008: nam='direct path write temp' ela= 1176 file number=203 first dba=392 block cnt=1 obj#=-1 tim=14331640040
WAIT #140512706274008: nam='direct path write temp' ela= 844 file number=203 first dba=393 block cnt=1 obj#=-1 tim=14331641358

FETCH #140512706274008:c=158,e=157,p=0,cr=0,cu=0,mis=0,r=15,dep=0,og=1,plh=44130803,tim=14345356617
WAIT #140512706274008: nam='SQL*Net message from client' ela= 3721 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=14345360474
WAIT #140512706274008: nam='SQL*Net message to client' ela= 4 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=14345360605
FETCH #140512706274008:c=0,e=87,p=0,cr=0,cu=0,mis=0,r=15,dep=0,og=1,plh=44130803,tim=14345360673
WAIT #140512706274008: nam='SQL*Net message from client' ela= 4547 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=14345365303
WAIT #140512706274008: nam='SQL*Net message to client' ela= 286 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=14345365981
FETCH #140512706274008:c=635,e=633,p=0,cr=0,cu=0,mis=0,r=5,dep=0,og=1,plh=44130803,tim=14345366311

FETCH ⇒ SQLNet message from client ⇒ SQLNet message to client の流れが確認できますね~彡(゚)(゚)

6-3. BINDSセクション(バインド変数)を生トレースで確認

DBMS_SESSION.SESSION_TRACE_ENABLE の binds => TRUE は、
SQLトレースにBINDSセクションを出力するオプションとなります。

下記は生トレースのBINDSサンプルです。

-- 生トレースのBINDSサンプル
:
BINDS #140512706270952:

 Bind#0
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=00 fl2=1000001 frm=00 csi=00 siz=48 off=0
  kxsbbbfp=7fcba3a6d150  bln=22  avl=03  flg=05
  value=715
 Bind#1
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=00 fl2=1000001 frm=00 csi=00 siz=0 off=24
  kxsbbbfp=7fcba3a6d168  bln=22  avl=02  flg=01
  value=5
:

バインド変数の取得&参照は完全な代替機能が無く、
生トレースの中では最もよく参照される箇所ではないでしょうか彡(゚)(゚)

6-4. STAT行(行ソース統計)を生トレースで確認

DBMS_SESSION.SESSION_TRACE_ENABLE の plan_stat => 'ALL_EXECUTIONS' は、
SQLトレースにSTAT行(行ソース統計)の出力を毎回強制するオプションとなります。

下記は生トレースのSTAT行サンプルです。


STAT #140512706274008 id=1 cnt=261 pid=0 pos=1 obj=0 op='SORT GROUP BY (cr=8926 pr=6669 pw=6669 str=1 time=13704807 us cost=30 size=208 card=8)'
STAT #140512706274008 id=2 cnt=26000 pid=1 pos=1 obj=0 op='HASH JOIN  (cr=8926 pr=6669 pw=6669 str=1 time=13880000 us cost=29 size=676 card=26)'
STAT #140512706274008 id=3 cnt=2600000 pid=2 pos=1 obj=79972 op='TABLE ACCESS FULL ORDER_TBL (cr=8835 pr=0 pw=0 str=1 time=378587 us cost=3 size=286 card=26)'
STAT #140512706274008 id=4 cnt=10 pid=2 pos=2 obj=79975 op='TABLE ACCESS FULL ITEM_TBL (cr=91 pr=0 pw=0 str=1 time=856 us cost=26 size=4500 card=300)'

デフォルト値ではSQLの初回実行のみSTAT行(行ソース統計)が出力されますが、
plan_stat => 'ALL_EXECUTIONS' で毎回出力できるようにするんですやね彡(゚)(゚)

7. まとめ

Standard Edition な環境でも、SQLトレースで闘える!彡(^)(^)
でも Tuning Pack(DBMS_SQLTUNE) は便利なんで、こちらもよろしくです。

SQLトレースはまだまだネタが多いですやね。TRCSESSユーティリティとか、
V$DIAG_TRACE_FILE や V$DIAG_TRACE_FILE_CONTENTS による動的ビューからのトレース採取とか。

こちらはまたの機会に。彡(゚)(゚)

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?