tech_memo / ORACLE / SQL_PLAN


tech_memo/ORACLE

実行計画の各ステップでかかった時間

  • 参考
  • dbms_sqltune.report_sql_monitorプロシージャを利用すると、EMのSQLリアルタイム監視と同等の情報が得られる
    set trimspool on
    set trim on
    set pages 0
    set linesize 1000
    set long 1000000
    set longchunksize 1000000
    
    spool sqlmon_active.html
    select dbms_sqltune.report_sql_monitor(sql_id=>'SQL_ID', type=>'active') from dual; -- ★typeはACTIVE(HTML) or TEXTを指定
    spool off
  • 上記プロシージャが情報をとってくる動的パフォーマンス・ビュー
    • V$SQL_MONITOR
    • V$SQL_PLAN_MONITOR
  • 単一の実行で最低5秒以上のCPU時間またはI/O時間を消費すると、監視対象としてエントリされ、情報を取得できるようになる。
    • 強制的に監視対象にするには、SQLにMONITORヒントを入れる
      select /*+ MONITOR */ COL1 from TBL1
    • 逆に強制的に監視対象外にするには、SQLにNO_MONITORヒントを入れる
      select /*+ NO_MONITOR */ COL1 from TBL1

過去のSQL実行時の実行計画の各ステップ所要時間を取得したい場合

  • 直近ではなく、過去のSQL実行時の監視情報を取得したい場合は、その時のsql_exec_idを特定して、repot_sql_monitorプロシージャの引数に指定すればよい。
  1. sql_exec_idの特定
    select dbms_sqltune.report_sql_monitor_list(sql_id=>'SQL_ID', type=>'TEXT') from dual; 
    • SQL実行日時と所要時間、sql_exec_id等が取得できる
  2. 上記で取得したsql_exec_idを指定して、SQLリアルタイム監視情報を取得
    select dbms_sqltune.report_sql_monitor(sql_id=>'SQL_ID', sql_exec_id=>'上記で取得したID', type=>'active') from dual; 

プラン・スタビリティ

  • 実行計画を実現するためのアウトライン「後で埋め込むためのヒント文の集まり」
  • SQLの実行計画のヒントセットを保存しておき、それを利用することにより、実行計画の固定化を促進できる機能。
  • 現在、非推奨(?)。SPMを利用することを薦められている
  • 参考

SPM (SQL Plan Management)

ヒント句


読み方

レコード単位か、テーブル単位か?

  • 以下のようなシンプルなテーブルが2つあり、
    create table TEST_1(ID NUMBER, STATUS CHAR(1));
    create table TEST_2(ID NUMBER);
  • HASH結合とフィルタを行ったとき、
    select /*+ use_hash(t1, t2) swap_join_inputs(t2) */
      t1.id
    from
      TEST_1 t1
    left join
      TEST_2 t2
    on
      t1.ID = t2.ID
    where
      t1.STATUS = '0' and t2.ID is not null or
      t1.STATUS = '1' and t2.ID is null
    ;
  • 以下のような実行計画が得られるが、
    Plan hash value: 1517313122
     
    ---------------------------------------------------------------------------------
    | Id  | Operation              | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
    ---------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT       |        |    82 |  2378 |     4   (0)| 00:00:01 |
    |*  1 |  FILTER                |        |       |       |            |          |
    |*  2 |   HASH JOIN RIGHT OUTER|        |    82 |  2378 |     4   (0)| 00:00:01 |
    |   3 |    TABLE ACCESS FULL   | TEST_2 |    82 |  1066 |     2   (0)| 00:00:01 |
    |   4 |    TABLE ACCESS FULL   | TEST_1 |    82 |  1312 |     2   (0)| 00:00:01 |
    ---------------------------------------------------------------------------------
     
    Predicate Information (identified by operation id):
    ---------------------------------------------------
     
       1 - filter("T1"."STATUS"='0' AND "T2"."ID" IS NOT NULL OR 
                  "T1"."STATUS"='1' AND "T2"."ID" IS NULL)
       2 - access("T1"."ID"="T2"."ID"(+))
  • Q. 上記のID=1のフィルタ処理は、ID=2の結合処理がすべて終わってから実行されるのか?それとも1レコードずつID=2 ⇒ ID=1の処理が行われるのか?
    • A. 上記SQLであれば、1レコードずつ、結合、フィルタが行われる。全レコードの平均より大きいなどの比較条件がある場合、全レコードの結合を待つ必要があるので、全レコード結合後、フィルタ処理が行われることになる。
      • どちらのケースが利用されるか、基本的には実行計画が作成された段階でどちらのケースを利用するかが決定される。

Predicate Information (フィルタ述語とアクセス述語)

  • 参考
  • フィルタ述語とアクセス述語
    • フィルタ述語
      • Predicate Informationではfilter(…)と記載され、行頭の番号に対応するオペレーションの実行時に、取得したデータから対象データを抜粋(フィルタ)する処理が実行されたことを示す。
    • アクセス述語
      • Predicate Informationではaccess(…)と記載され、行頭の番号に対応するオペレーションの実行時に、表示された述語を使用してデータにアクセスしたことを示す。一般に索引スキャン実行時に指定される。
    • 下記は、TEST2_IX1インデックスを利用して、NUM=1の行を取得している(アクセス述語が指定されている)
      ------------------------------------------------------------------------------
      | Id  | Operation        | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
      ------------------------------------------------------------------------------
      |   0 | SELECT STATEMENT |           |     1 |     4 |     1   (0)| 00:00:01 |
      |*  1 |  INDEX RANGE SCAN| TEST2_IX1 |     1 |     4 |     1   (0)| 00:00:01 |
      ------------------------------------------------------------------------------
       
      Predicate Information (identified by operation id):
      ---------------------------------------------------
       
         1 - access("NUM"=1) # ★アクセス述語

実行計画 項目

INDEX

  • INDEXスキャンの実行計画操作の種類
    操作オプション操作の内容マニュアルに記載されたバージョン
    INDEXUNIQUE SCANB-Tree 索引 からユニークキーを使用して1つの ROWID を取得する8.0 以前
    RANGE SCAN索引から範囲(スタート・キー、ストップ・キー)をキーにして1または複数 ROWID の取得
    RANGE SCAN DESCENDINGINDEX RANGE SCAN を索引値の降順にスキャン
    FULL SCAN索引からのすべての ROWID の取得。遅い(テーブルフルスキャンよりマシ)。利点は、INDEXの順にアクセスするので、ソート済みの状態でデータが取得できるOracle 9i Release2
    FULL SCAN DESCENDINGINDEX FULL SCAN を索引の降順で行なう
    FAST FULL SCANINDEX FULL SCAN の高速版:マルチブロック読み込みを使用するため取得順番は不定。インデックスに全カラムが含まれている場合 TABLE FULL SCAN と同じ意味になる(※ つまり ROWID だけでなくカラム値も取得する)Oracle 9i Release2 CBO のみ
    SKIP SCANINDEX SKIP SCAN を使用した ROWID の取得

テーブル結合方法

HASH結合メモ

  • 小規模表(A)と大規模表(B)のIndexスキャンについて

AWRレポートのSQL_IDを使って実行計画を取得

  • AWRレポートのSQL Idを利用して、以下のSQLで実行計画が取得できる
    select * from table(DBMS_XPLAN.DISPLAY_AWR('<SQL_ID>',null,null,'ALL'));
  • AWRレポート抜粋
            Elapsed                  Elapsed Time
            Time (s)    Executions  per Exec (s)  %Total   %CPU    %IO    SQL Id
    ---------------- -------------- ------------- ------ ------ ------ -------------
            43,399.6         18,049          2.40   19.4     .9     .0 6qb74qdmz6jxw
    Module: JDBC Thin Client
    SELECT MY_ID FROM MY_TABLE WHERE MY_ID IN ( 以下略

V$SQL_PLANから実行計画を取得

実行計画の取得


EXPLAIN PLAN

  1. 実行計画を解析
    EXPLAIN PLAN FOR <実行計画を取得したSQLテキスト>;
  2. DBMS_XPLAN.DISPLAY()から実行計画を取得
    SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY())

set autotrace

  • 内部的にはEXPLAIN PLAN FORを呼び出している
  • set autotrace on explain
    • 実行結果と実行計画を表示する。
  • set autotrace on statistics
    • 実行結果と実行時統計情報を表示する。
  • set autotrace on
    • 実行結果と実行計画、統計情報を表示する。
  • set autotrace traceonly
    • 実行計画と統計を表示する。実行結果は表示しない。
  • set autotrace off
    • autotrace をオフにする。

バインド変数を含んだSQLの実行計画の取得

EXPLAIN PLAN(set autotrace)で取得できる実行計画は正確ではない!?

  • 参考
  • 実際の実行計画と、EXPLAIN PLANで取得する実行計画には差分が生じる場合がある
    • クライアント環境の差異
      • 実SQLはJavaから実行されるが、EXPLAIN PLANはSqlplusから実行している
    • バインド変数のバインドピークON/OFFの差異
      • バインドピークとは? ⇒ バインド変数の中身を展開してから実行計画を作成する。ただし、共有プールにキャッシュされている場合は、これは行われない。
      • ちなみに、バインドピークOFFの場合は、Oracleデフォルトのヒット率が利用される(範囲検索の場合は5%ヒット)
      • バインド変数 ON ⇒ 共有プールから実行計画が削除された後、再度同じSQL(バインド変数の中身は違う)を発行した場合、実行計画が変わる可能性がある
      • バインド変数 OFF ⇒ 実行計画は変わりにくいが、バインド変数値がOracle判断になるので、最適でない実行計画になる可能性がある
      • EXPLAIN PLANではバインドピークは実行されない
      • 実際に実行したときのバインドピークの実行有無は、隠しパラメータ「_optim_peek_user_binds」で設定(TRUEであれば実行)
  • 正確な実行計画を取得するには、DBMS_XPLAN.DISPLAY_CURSOR()を利用して、Oracleの共有プールの実行計画を見る
    SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('<SQL_ID>', NULL, 'ALL'));

INDEXスキャンしやすくする

  • optimizer_index_cachingとoptimizer_index_cost_adjパラメータを調整する。

最新の20件

2023-01-26 2022-11-11 2022-03-02 2022-02-03 2021-11-18 2021-11-11 2021-10-27 2021-10-04 2021-09-30 2021-08-24 2021-04-01 2021-02-25 2020-08-13 2020-05-22 2020-04-16 2020-04-15 2020-03-23 2020-03-12 2020-02-27

今日の6件

  • counter: 964
  • today: 1
  • yesterday: 0
  • online: 1