GAGA LIFE.

インフラエンジニアブログ

スポンサーリンク

Oracle 実行計画の取得方法の選択について

概要

Oracleで実行計画を取得する方法をまとめました。
※普段は、SQLチューニング依頼を受けた場合にはDBMS_XPLAN.DISPLAY_CURSORを使用しています。

方法

  1. EXPLAIN PLAN+DBMS_XPLAN
  2. AUTOTRACE(SQL*Plus)
  3. DBMS_XPLANパッケージ(CURSOR/AWR)
  4. 動的パフォーマンスビュー(V$SQL_PLAN/V$SQL/V$SQL_TEXT)
  5. SQLトレース+tkprof
  6. リアルタイムSQL監視

上記5にはさらに以下があります。

  • SQL_TRACE(11gR1-)
  • 10046トレース
  • DBMS_MONITOR

取得方法まとめ

方法 取得工数(手間) システム負荷 実行統計 Actual値の取得 ライセンス要否
EXPLAIN PLAN × Estimate 不要
AUTOTRACE Actual 不要
DBMS_XPLAN Actual 要(※Diagnostic Packライセンス)
V$ビュー × Actual 不要
SQLトレース SQL_TRACE(11gR1-) Actual 不要
EVENT10046 Actual 不要
DBMS_MONITOR Actual 要(※Tuning Packライセンス)
リアルタイムSQL監視 Actual 要(※Tuning Packライセンス)

補足

Actual(実行):
   過去、SQL実行で実際に使用された実行計画・実行統計を表示
Estimate(見積):
   Oracleが予測で見積もった実行計画・実行統計を表示。
   そのため、実行時の実行計画と異なる可能性あり

なお、DBMS_XPLANは、利用方法によってEstimate/Actualが異なります。

  パターン1.EXPLAINとの併用 実行計画:Estimate/実行統計:Actual
  パターン2.SQL実行後の取得 実行計画:Actual/実行統計:Estimate
  パターン3.STATISTICS_LEVEL=ALL+format句にALLSTATS LAST
                  実行計画:Actual/実行統計:Estimate&Actual

その他の取得方法

  • STASPACK/AWR SQLレポート
  • SQLHC
  • SQLTXPLAIN(SQLT)
  • EVENT10053→※CBOトレースですが、実行計画情報も含まれます

        ...他多数

メリット/デメリット

No 取得方法 メリット/デメリット
1 EXPLAIN+DBMS_XPLAN <メリット>
  • SQLを実行しない(PARSEのみ)ため、PLANを即時に確認可能
  • Client側(SQL*Plus等)のみで作業が完結可能
  • PLANの詳細情報の確認可能(パラレル・クエリ等)
  • バインド変数を設定しなくてもPLANの確認が可能
  • DMLであっても実行せずにPLANの取得可

<デメリット>

  • EXPLAINで確認したPLANと実行時のPLANに差異がある場合がある
2 AUTOTRACE <メリット>
  • PLANの取得と実行統計の取得がSQL*PLUSのみで完結するため取得工数が少ない
<デメリット>
  • PLANの確認は、SQL完了まで待つ必要がある
  • SQL*Plusでのみの使用となる
  • PLANの出力は、内部的にはEXPLAIN PLANが実行されているため実行時のPLANと異なる場合がある
  • 「SET AUTOTRACE TRACEONLY」を実行しても(あくまでSQL*Plusの表示上の範囲のため)SQLが実行されてしまう
3 DBMS_XPLAN <メリット>
  • EstimateとActualの双方が取得可能(format句による)
  • 事前設定が少ないため、比較的に簡易に取得可能
  • 「Predicate Information」等の追加情報が得られる

<デメリット>

  • CURSORの場合、共有プール上に存在しない場合、情報が取得できない
4 V$ビュー <メリット>
  • (権限が付与されていれば)簡易に取れるため、取得工数が少ない
<デメリット>
  • 実行統計は取得できない
5 SQLトレース <メリット>
  • 出力されるPLANが実行時のPLAN(Estimateではない)
  • PLANと併せて実行統計(経過時間/ブロック読込量/待機イベント)も取得可能

<デメリット>

  • PLANの出力は、SQLが完了するまで待つ必要がある
  • SQLコマンドとOSコマンド(tkprof)が混在するため手順が増える
6 リアルタイムSQL監視 <メリット>
  • 取得に伴うオーバーヘッドが少ない
  • GUIから容易にボトルネックとなっている処理が特定できる
  • SQLの終了待たず、実行中にPLANや実行統計が確認可能

<デメリット>

  • (MONITORヒント)を付与していない場合、5秒以内のSQLは監視にかからない

参考資料

--V$ビュー

http://odakeiji.blog33.fc2.com/blog-entry-23.html

--リアルタイムSQL監視

http://www.oracle.com/technetwork/jp/ondemand/db-basic/d-16-ssqltuning-1448439-ja.pdf

--その他
Oracle SQL Tuning with Oracle SQLTXPLAIN: Oracle Database 12c Edition

Oracle SQL Tuning with Oracle SQLTXPLAIN: Oracle Database 12c Edition

Oracle SQL Tuning with Oracle SQLTXPLAIN: Oracle Database 12c Edition

 

--全体
Expert Oracle SQL 

Expert Oracle SQL: Optimization, Deployment, and Statistics

Expert Oracle SQL: Optimization, Deployment, and Statistics

 

Cost-Based Oracle Fundamentals 

Cost-Based Oracle Fundamentals (Expert's Voice in Oracle)

Cost-Based Oracle Fundamentals (Expert's Voice in Oracle)

 

Pro Oracle SQL, Second Edition 

Pro Oracle SQL (Expert's Voice in Oracle)

Pro Oracle SQL (Expert's Voice in Oracle)

  • 作者: Karen Morton,Kerry Osborne,Robyn Sands,Riyaj Shamsudeen,Jared Still
  • 出版社/メーカー: Apress
  • 発売日: 2013/10/29
  • メディア: ペーパーバック
  • この商品を含むブログを見る
 

Troubleshooting Oracle Performance, Second Edition 

Troubleshooting Oracle Performance

Troubleshooting Oracle Performance

 

Oracle® Database SQLチューニング・ガイド 12cリリース2 (12.2)

http://www.doppo1.net/oracle/tuning/explain-plan.html#2

https://www.ashisuto.co.jp/db_blog/article/20160630_sqltrace.html

http://d.hatena.ne.jp/yohei-a/20160605/1465079548

http://www.intellilink.co.jp/article/column/ora-report20150507.html

Oracle 統計情報の収集(DBMS_STATSの各プロシージャのパラメータ)

概要

統計情報の収集のために、DBMS_STATSパッケージにはいくつかのプロシージャが用意されていますが、それぞれの特徴やパラメータについてまとめます。

各プロシージャについて

システム特性や取得対象に応じてデータベース全体/データディクショナリ/スキーマ/単一オブジェクトに対して統計情報を収集するプロセスが発生する必要があり、いくつかのプロシージャがあります。

プロシージャ 説明
gather_database_stats データベース全体のオブジェクト統計を収集
gather_dictionary_stats データディクショナリの統計を収集
データディクショナリは、sysスキーマに格納されているオブジェクトで構成されているだけでなく、オプションのコンポーネント用にOracleによってインストールされた他のスキーマも含みます。
gather_fixed_objects_stats 固定表(X$表)とデータディクショナリの一部である特定のオブジェクトの統計を収集
動的パフォーマンスビューでよく使用される固定表メモリ構造のみです。
どの表がこのプロシージャに関連しているかを知るには、v$fixed_tableを確認することで確認可能です。
※ただし、固定されたテーブルごとにオブジェクト統計が収集されるわけではない
gather_table_stats スキーマ全体のオブジェクト統計を収集
gather_table_stats 列を含む1つの表、およびオプションで索引のオブジェクト統計を収集
gather_index_stats 1つの索引のオブジェクト統計を収集

Note:
統計情報の収集は、DBMS_STATSパッケージの使用以外にも動作しています。
例えば、CREATE INDEXおよびALTER INDEX文は、索引作成の際に統計情報を自動的に収集します。
さらに、12.1以降では、CTAS文と空テーブルへのDIRECT PATH INSERTにより、統計が自動的に収集されます。
※DBMS_STATSパッケージによる統計の計算は、自動的に収集されたものより優れている可能性があることに注意

各パラメータの範囲と使用方法

  • DBMS_STATSパッケージによって提供されるプロシージャには、3つの主要なカテゴリに
    グループ化できるいくつかのパラメータがあります。
    • 第1グループ:ターゲットオブジェクトの指定
    • 第2グループ:収集オプションの指定
    • 第3グループ:現在の統計を上書きする前にバックアップするか否かの指定

統計収集に使用されるプロシージャのパラメータ

Parameter Database Dictionary Fixed Objects Schema Table Index
Taget Objects
ownname
indname
tabname
partname
comp_id
granularity
cascade
gather_fixed
gather_sys
gather_temp
options ✓*
objlist
force
obj_filter_list
Gathering Options
estimate_percent
block_sample
method_opt
degree
no_invalidate
Backup Table
stattab
statid
statown

✓*12.1から利用可能

参考資料


Troubleshooting Oracle Performance, Second Edition

Troubleshooting Oracle Performance

Troubleshooting Oracle Performance


Oracle® Database PL/SQLパッケージおよびタイプ・リファレンス 12c リリース2 (12.2)

Oracle オブジェクト統計

概要

統計情報の管理や、統計情報の不備による実行計画変化で性能劣化を招いた場合の対処として、オブジェクト統計に関する知識は必須なため、 その知識習得のキッカケとして種類や確認するビューなどを記載します。

  • オブジェクト統計には、下記の3種類があります。
    • 表統計
    • 列統計
    • 索引統計
  • さらに各タイプには、下記の3つのタイプがあります。
    • 表/索引レベルの統計
    • パーティション・レベルの統計
    • サブパーティション・レベルの統計 パーティションとサブパーティションの統計は、オブジェクトがそれぞれ分割され、サブパーティション化されている場合にのみ存在します。

オブジェクト統計は、下記の表のようなデータ・ディクショナリ・ビューに表示されます。
各ビューには、dba_all_、がそれぞれ存在しています。
また、12.1マルチテナント環境では、dba_tab_statistics/all_tab_statistics/cdb_tab_statistics等のcdbバージョンもあります。

オブジェクト統計に関するデータ・ディクショナリ・ビュー

Object Table/Index-Level Statistics Partition-Level Statistics Subpartition-Level Statistics
Tables user_tab_statistics user_tab_statistics user_tab_statistics
Indexes user_ind_statistics user_ind_statistics user_ind_statistics
Columns user_tab_col_statistics
user_tab_histgrams
user_part_col_statistics
user_part_histgrams
user_subpart_col_statistics
user_subpart_histgrams

参考資料

Troubleshooting Oracle Performance, Second Edition

Troubleshooting Oracle Performance

Troubleshooting Oracle Performance


Oracle® Databaseリファレンス 12cリリース2 (12.2)
https://docs.oracle.com/cd/E82638_01/REFRN/toc.htm

Oracle 統計情報の種類

概要

Oracleの統計情報について簡単にまとめます。
これらの精度を高めることがよりよい実行計画を生成する可能性を高めることにつながります。

Oracleの統計情報の種類とそれぞれの特徴

種類 概要 未取得時の影響 取得方法
オブジェクト統計 表統計 表に対する統計
  • 表(パーティション)の行数
  • 表内に格納されたHWM以下に存在するデータブロック数
  • 表内の行の長さの平均
  • 行連鎖/行移行が発生している行数 など
非効率な実行計画が生成される可能性がある DBMS_STATS.GATHER_TABLE_STATS
索引統計 索引に対する統計
  • ルート・ブロックからリーフ・ブロックまでの索引の高さ
  • 索引に含まれるリーフ・ブロックの数
  • クラスタ化係数
  • 索引キー値の種類の数 など
同上 DBMS_STATS.GATHER_INDEX_STATS
列統計 列に対する統計
  • 列内に含まれる値の種類
  • 値がNULLの行数
  • 列の最小値/最大値
  • 列内に格納されたデータの分布度 など
同上

DBMS_STATS.GATHER_TABLE_STATS

※method_opt引数で制御

システム統計 システムのI/O性能やCPU速度の統計情報
※NOWORKLOAD統計/WORKLOAD統計がある
サーバーのリソース状況に合った実行計画が生成されない可能性がある DBMS_STATS.GATHER_SYSTEM_STATS();
ディクショナリ統計 データディクショナリの統計情報
  • 再帰的SQLやユーザSQLのハードパース時に長時間化する可能性がある
  • バックグラウンドプロセスの内部SQL/EM/AWRなどが発行するSQLで不適切な実行計画が選択される可能性がある
DBMS_STATS.GATHER_DICTIONARY_STATS();
固定オブジェクト統計 V$ビューなどの動的パフォーマンスビューのもととなるX$表などの固定オブジェクトの統計情報 同上 DBMS_STATS.GATHER_FIXED_OBJECTS_STATS();

参考資料

Expert Oracle SQL

Expert Oracle SQL: Optimization, Deployment, and Statistics

Expert Oracle SQL: Optimization, Deployment, and Statistics

 

Oracle 結合方法と結合タイプ

はじめに

Oracleの結合方法/結合タイプについて記載します。

結合アルゴリズム

結合アルゴリズム 日本語 ヒント句
Nested Loops Joins ネステッド・ループ結合 USE_NL/NO_USE_NL/USE_NL_WITH_INDEX
Hash Joins ハッシュ結合 USE_HASH/NO_USE_HASH
Sort Merge Joins ソートマージ結合 USE_MERGE/NO_USE_MERGE
Merge Join Cartesian デカルト結合(直積)  

結合タイプ

結合タイプ 日本語 Nested Loops Joins Hash Joins Sort Merge Joins
Cross Join クロス結合  
Semi/anti-join セミ/アンチ結合
Outer join 外部結合  
inner join(theta Join) 内部結合  
Equi-join 等価結合
Band join バンド結合    

各結合アルゴリズムの概要

Nested Loops Joins(ネステッド・ループ結合)

f:id:undercovergeek:20180605223857j:plain

▽動作

  • ループ処理をネスト(入れ子構造)にして結合処理を実行
  • 外部ループで参照される表=外部表。内部ループで参照される表=内部表
  • 外部表の返却行数分、内部表に対するループ処理が発生するため、外部表は駆動表とも呼ばれる
  • はじめに外部表にアクセスする
  • 外部表から戻された行数分、内部表にアクセスし、条件に合致するデータを返却する

▽特徴

  • カーディナリティが小さい表を外部表とする
  • 外部表のカーディナリティが内部表の参照回数となる
  • 実レコード件数ではなくカーディナリティが小さい表を外部表とする
  • 内部表のアクセス効率を上げる
  • 内部表の結合列に索引があると効率的

▽パフォーマンス

  • 処理回数のみを考慮した場合、外部表から返される行数が少なれければ内部表に対するループ回数が減るため、条件指定で返却行数が少ない表を外部表に指定する(カーディナリティが小さい表を外部表に指定する)
  • 外部表からの返却行数が少ない場合でも内部表を全件検索せざるを得ない場合はパフォーマンスが悪い
  • 内部表に対する絞込み条件と外部表との結合条件で索引が効率的に使用されているか等、内部表に対するアクセス方法を考慮する必要がある
Hash Joins(ハッシュ結合)

f:id:undercovergeek:20180605223853j:plain

▽動作

  • 表1から抽出条件に合致する結果セットを返却
  • 結果セットの結合キーを基にハッシュ表をPGA内に作成
  • 表2から絞込み条件に合致する結果セットを返す
  • 結果セットの結合キーを順にハッシュし、ハッシュ表と照合し結合条件に合致する行を特定

▽特徴

  •  カーディナリティが小さい方を先に処理する(PGAに作成)
  • PGA上に作成される表が小さくなるため、結合処理が効率的
  • 一時表領域へのI/Oが発生する可能性がある
  • ハッシュ表がメモリ内に収まらない場合には一時表領域を使用するためディスクI/Oの発生により性能が劣化する可能性がある
    ⇒PGA_AGGREGATE_TARGETまたはHASH_AREA_SIZEを考慮する
  • 等価条件でのみ使用される
  • 結合条件が等価結合でない(範囲指定)場合、ハッシュ結合は使用されない
  • アクセス方法はフルスキャン
  • 必ず表のフルスキャン、または索引フルスキャン

▽パフォーマンス 

   ・一方の表から結合キーをもとにメモリ内(PGA)にハッシュテーブルを構築した際、ハッシュテーブルがPGA内で収まりきれない場合、一時表領域(TEMPファイル)を使用して他方の表と結合処理が行われる。そのため、他方の結合キーによっては、TEMPファイルに対するディスクI/Oが発生するのでその分がオーバヘッドになる

Sort Merge Joins(ソート・マージ結合)

f:id:undercovergeek:20180605223900j:plain

▽動作

  • 表1の結果セットを結合列でPGA内でソート
  • 表2の結果セットを結合列でPGA内でソート
  • ソート処理はシリアル実行
  • ソート結果をPGA内でマージして結果を返却

▽特徴

  • 一時表領域(Tempファイル)へのI/Oが発生する可能性がある
  • ソート処理がメモリ内に収まらない場合、一時表領域を使うためディスクI/Oの発生し、性能劣化が発生する可能性がある
    ⇒PGA_AGGREGATE_TARGETまたはSORT_AREA_SIZEを考慮する
  • 表1は一定条件でソート処理が回避できる(表2のソートは回避できない)
  • 表1は、結合列に索引が定義され、かつNOT NULL制約が存在する場合、索引フルスキャンを実行することでソート処理を回避可能
  • 表2は、ソートを実行しながら結合を進めるため、ソート処理は回避できない

▽パフォーマンス

  • 各表の結合キーがソートされてPGA内に保持されるため、ソートに必要な領域がPGA内で収まりきれない場合、一時表領域のTEMPファイルが使用される。ソートされた結合キー同士をマージするときに、ディスクI/Oが発生し、その分がオーバヘッドとなる
Merge Join Cartesian(デカルト積)

f:id:undercovergeek:20180605223903j:plain

▽動作

  • 結果セット1の全行と結果セット2の全行を直積(掛け算)
  • 3表以上の結合が行われる場合、結合条件が存在する場合でも直積結合が選択される場合もある。直接の結合関係にない小さな表同士の直積結合を行い、結合条件のある一方の表と結合するような場合も有り得る

▽特徴

  • 2つの行ソースに対する結合条件がない場合に直積が選択される
  • 結合条件に漏れがないかを確認

▽パフォーマンス

  • 一般的に直積はパフォーマンスが悪いが、スタースキーマ構造となっているDWHシステムでは有効な場合がある

各結合タイプの概要

クロス結合(直積/デカルト積)
  • 2つの表を結合する際に結合条件を明記しない場合に選択される。
  • Oracleは1番目の表の各行と2番目の表の各行を結合する。
  • 直積の行数は1番目の表の行数と2番目の表の行数を掛けた数になる。
内部結合(単純結合)
  • 2つ以上の表を結合し、その結合条件を満たす行のみを返却する。
  • 一般的に結合と言う場合、内部結合を指す。
外部結合
  • 結合される両方の表が結合条件を満たす行も、一方の表には条件を満たす行がない行も全て返却する。
  • 外部結合は内部結合の結果を拡張した位置づけ。
等価結合/非等価結合
  • 等価結合は、結合条件に等価演算子を含む構文のことを言う。
  • 等価結合は、ある特定の列の値が等しい行を結び付ける。
  • 等価演算子以外の演算子で2つの表が結合されている場合は非等価結合。
  • 問合せ文には非等価結合と等価結合も含むことが可能。
自己結合
  • 対象表自身を結合する方法。
  • 自己結合する表はFROM句で2回(あるいはそれ以上)指定され、各表名の後ろには、結合条件やSELECT句の列名を修飾する別名が続く。
アンチジョイン
  • NOT EXISTS句やNOT IN句を用いて記述する。結合条件と一致しない組み合わせを返却する
  • 2つの表をアンチ結合した場合、最初に記述された表に存在し、後に記述された表には存在しない行を返す(右側の副問合せとの結合に失敗した行を戻す)
セミジョイン
  • EXISTS句やIN句を用いて記述する。一致する行が1つ見つかると値を返す。
  • 2つの表を半結合した場合、最初に記述された表に存在する行で、後に記述された表に1行ないしは複数行存在する行を戻す。
  • 半結合と従来の結合との違いは、最初に記述される表の行と一致する行が、後ろに記述される表に複数行存在する場合でも1行しか戻されないという点。
その他
バンド結合(12.2~)
  • 1つのデータセットのキー値が2番目のデータセットの指定された範囲(「バンド」)内になければならない特別なタイプの非等価関数。
  • 同じテーブルは、第1および第2のデータセットの両方として機能することが可能。
  • 12.2以降、データベースはバンド結合をより効率的に評価する。
  • 最適化は、定義されたバンドの外にある行の不必要なスキャンを回避する。
  • オプティマイザはコスト見積もりを使用して、結合方法(ハッシュ/ネストループ/ソートマージ)とパラレルデータ分散方法を選択する。

参考資料

https://docs.oracle.com/cd/E82638_01/TGSQL/toc.htm
Expert Oracle SQL

Expert Oracle SQL: Optimization, Deployment, and Statistics

Expert Oracle SQL: Optimization, Deployment, and Statistics

 

SQL実践入門──高速でわかりやすいクエリの書き方 

SQL実践入門──高速でわかりやすいクエリの書き方 (WEB+DB PRESS plus)

SQL実践入門──高速でわかりやすいクエリの書き方 (WEB+DB PRESS plus)

 

Oracle B-treeインデックスアクセス

はじめに

B-treeインデックスを使用したテーブルアクセスの方法についてまとめます。

B-treeインデックスアクセス方式

操作 ヒント 代替ヒント
INDEX FULL SCAN INDEX  
INDEX FULL SCAN (MIN/MAX) INDEX  
INDEX FULL SCAN DESCENDING INDEX_DESC  
INDEX RANGE SCAN INDEX INDEX_RS_ASC
INDEX RANGE SCAN DESCENDING INDEX_DESC INDEX_RS_DESC
INDEX RANGE SCAN (MIN/MAX) INDEX  
INDEX SKIP SCAN INDEX_SS INDEX_SS_ASC
INDEX SKIP SCAN DESCENDING INDEX_SS_DESC  
INDEX UNIQUE SCAN INDEX INDEX_RS_ASC
INDEX FAST FULL SCAN INDEX_FFS  
INDEX SAMPLE FAST FULL SCAN INDEX_FFS  
HASH JOIN INDEX_JOIN  
AND-EQUAL AND_EQUAL  

各アクセス方法の概要

INDEX FULL SCAN・INDEX FULL SCAN (MIN/MAX)・INDEX FULL SCAN DESCENDING

f:id:undercovergeek:20180602182810j:plain

▽特徴
  • リーフ・ブロックを全て走査し、条件に合致するエントリを返却
  • リンク順にスキャンするため、キー値でソートされた値にエントリを返却
  • 返却値がソートされているため、その後のソートを回避できる可能性がある
▽SQLの条件
  • INDEX FULL SCANは、SQLの条件で索引列の値が選択されている必要はありません。
  • 索引のFULLスキャンが選択される条件は、SQLで参照される列が全て索引に含まれている場合、かつ少なくても索引列の一つにNOT NULL制約が付いている場合です。
  • INDEX FULL SCANが選択されるのは、索引列のみの参照でソート処理が必要な場合に、表データをFULLスキャンしてソートするのではなく、ソート済みの索引のFULLスキャンしてソート処理が回避できます。ルート、ブランチブロックからリーフブロック全体を検索します。
▽留意点
  • INDEXの全ブロックがシーケンシャルアクセス(1ブロックずつ読み込まれる)される
INDEX RANGE SCAN・INDEX RANGE SCAN DESCENDING・INDEX RANGE SCAN (MIN/MAX)

f:id:undercovergeek:20180602183022j:plain

▽特徴
  • キー値の範囲でリーフ・ブロックを走査し、条件に該当する複数エントリを返却
  • ルート、ブランチブロックから選択範囲内のリーフブロックを検索する
  • 該当するリーフブロック内のROWIDをもとに実際の表データを参照
  • SQLが索引列のみを必要としている場合は、表データへの参照は行われず、リーフブロック内に格納されているデータから値を返す
▽SQLの条件
  • 索引が定義された列に対して範囲条件(例:BETWEEN,<,>)を指定した場合
  • 非一意索引の場合は、等価条件でもINDEX RANGE SCANが選択される
▽留意点
  • 索引は索引列がソートして格納されているため、索引を使用してORDER BY句を満たせる場合は、ソート処理を回避することも可能
INDEX SKIP SCAN・INDEX SKIP SCAN DESCENDING

f:id:undercovergeek:20180602183114j:plain

▽特徴
  • 複数列で作成されたINDEXが、SQLの条件内でINDEX列の第一列が指定されていない場合でもINDEXスキャンを実施することが可能
  • 内部的に、第一列の値をもとに論理的な副索引を作成して索引スキャンを可能にしている
  • 第一列の値をもとに副索引が作成されるため、第一列の値の個別値が非常に少ない場合に有効に動作する
  • 索引数を減らすことで、表データの更新処理を効率化することも可能
▽SQLの条件
  • 複合索引の第一列目に対する条件指定が無く、2列目以降の列に対して条件指定があった場合に採用される可能性がある
▽留意点
  • INDEX RANGE SCANと比較して効率が悪いアクセス方法
INDEX UNIQUE SCAN

f:id:undercovergeek:20180602183246j:plain

▽特徴
  • 条件に合致する1エントリを返却
  • ルート、ブランチブロックから単一値の範囲内のリーフブロックを検索
  • 該当するリーフブロック内の1つのROWIDをもとに実際の表データを参照する
  • SQLがINDEX列のみを必要としている場合には、表データへの参照は実行されず、リーフブロック内に格納されているデータから値を返す
▽SQLの条件
  • 単一の値が選択されるような場合(列が等価条件で指定されている)に使用される
▽留意点
  • 単一の値が選択される条件としては、該当する表の列に対し、一意制約または主キー制約が存在する必要がある
INDEX FAST FULL SCAN・INDEX SAMPLE FAST FULL SCAN

f:id:undercovergeek:20180602183308j:plain

▽特徴
  • ツリー構造を意識せずに、セグメント・ヘッダから順にブロックをフルスキャンする
  • 返却値はソートされていない
  • マルチ・ブロック・リードやパラレル実行が可能
▽SQLの条件
  • SQLの条件で、索引列の値が選択されている必要はない
  • INDEX FAST FULL SCAN選択の条件は、SQLで参照される列が全て索引に含まれている場合、かつ少なくとも索引列の一つがNOT NULL制約が付いている場合
  • 索引のFULLスキャンと同じ条件
▽留意点
  • INDEX FULL SCANとの差異としてはソート処理の有無。INDEX FULL SCANは、索引の構造を利用したソート処理の回避が可能だが、INDEX FAST FULL SCANは、ソート処理の回避ができない
  • 索引ブロックを先頭エクステントから格納順にアクセスしていく方法なので返ってくる結果は索引キーの順にソートされていない

その他

HASH JOIN(INDEX JOIN)
▽特徴
  • 複数の索引を結合アクセスするアクセスパス
  • 結合した索引のみを参照するため高速
▽SQLの条件
  • 索引が結合されている表から必要な列のみが索引に存在する列である場合にのみ可能
▽留意点
  • 問合せに必要な列が索引に含まれている必要がある
  • 2つの索引を統合した複合索引を作成したほうが、より性能面で効果的な場合が多い
AND-EQUAL
▽特徴
  • 複数の列それぞれのB-tree Indexから取得したROWIDをマージし、テーブルからレコードを取得する
▽SQLの条件
  • AND_EQUALヒントが必要
▽留意点
  • インデックスが単一列の一意でないインデックスである必要がある
  • 廃止予定の機能

実行例

事前準備

CREATE TABLE t1
(
   c1 NOT NULL
  ,c2 NOT NULL
  ,c3 NOT NULL
  ,c4 NOT NULL
  ,c5 NOT NULL
  ,c6 NOT NULL
)
AS
     SELECT ROWNUM
           ,ROWNUM
           ,ROWNUM
           ,ROWNUM
           ,ROWNUM
           ,ROWNUM
       FROM DUAL
  CONNECT BY LEVEL < 100;

CREATE INDEX t1_i1 ON t1 (c1, c2);


INDEX FULL SCAN

SQL> explain plan for
   2 SELECT /*+ index(t1 (c1,c2)) */ * FROM t1;

Explained.

SQL> select * from table(dbms_xplan.display(format=>'BASIC'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------
Plan hash value: 1188580999

-----------------------------------------------------
| Id | Operation                           | Name   |
-----------------------------------------------------
|  0 | SELECT STATEMENT                    |        |
|  1 |  TABLE ACCESS BY INDEX ROWID BATCHED| T1     |
|  2 |   INDEX FULL SCAN                   | T1_I1  |
-----------------------------------------------------

<補足>

TABLE ACCESS BY INDEX ROWID BATCHED:
12cからの機能で「BATCH TABLE ACCESS BY ROWID」と呼ばれる動作。
表にBATCHアクセスするため、アクセス対象のデータブロック数が多い場合に効果的な機能

INDEX FULL SCAN (MIN/MAX)

SQL> explain plan for
   2 SELECT /*+ index(t1 (c1,c2)) */ MAX (c1) FROM t1;

Explained.


SQL> select * from table(dbms_xplan.display(format=>'BASIC'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------
Plan hash value: 1743745495

--------------------------------------------
| Id | Operation                  | Name   |
--------------------------------------------
| 0  | SELECT STATEMENT           |        |
| 1  |  SORT AGGREGATE            |        |
| 2  |   INDEX FULL SCAN (MIN/MAX)| T1_I1  |
--------------------------------------------

INDEX FULL SCAN DESCENDING

SQL> explain plan for
   2 SELECT /*+ index_desc(t1 (c1,c2)) */ * FROM t1 ORDER BY c1 DESC, c2 DESC;

Explained.

SQL> select * from table(dbms_xplan.display(format=>'BASIC'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------
Plan hash value: 4270362996

---------------------------------------------
| Id | Operation                   | Name   |
---------------------------------------------
| 0  | SELECT STATEMENT            |        |
| 1  |  TABLE ACCESS BY INDEX ROWID| T1     |
| 2  |   INDEX FULL SCAN DESCENDING| T1_I1  |
---------------------------------------------

INDEX RANGE SCAN

SQL> explain plan for
   2 SELECT /*+ index(t1 (c1,c2)) */ * FROM t1 WHERE c1 BETWEEN 3 AND 5;

Explained.

SQL> select * from table(dbms_xplan.display(format=>'BASIC'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------
Plan hash value: 3320414027

-----------------------------------------------------
| Id | Operation                           | Name   |
-----------------------------------------------------
| 0  | SELECT STATEMENT                    |        |
| 1  |  TABLE ACCESS BY INDEX ROWID BATCHED| T1     |
| 2  |   INDEX RANGE SCAN                  | T1_I1  |
-----------------------------------------------------

INDEX RANGE SCAN DESCENDING

SQL> explain plan for
   2 SELECT /*+ index_desc(t1 (c1,c2)) */ * FROM t1 WHERE c1 BETWEEN 3 AND 5 ORDER BY c1 DESC;

Explained.

SQL> select * from table(dbms_xplan.display(format=>'BASIC'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------
Plan hash value: 891765463

----------------------------------------------
| Id | Operation                    | Name   |
----------------------------------------------
| 0  | SELECT STATEMENT             |        |
| 1  |  TABLE ACCESS BY INDEX ROWID | T1     |
| 2  |   INDEX RANGE SCAN DESCENDING| T1_I1  |
----------------------------------------------

INDEX RANGE SCAN (MIN/MAX)

SQL> explain plan for
   2 SELECT /*+ index(t1 (c1,c2)) */ MIN (c2) FROM t1 WHERE c1 = 3 ORDER BY c1 DESC;

Explained.

SQL> select * from table(dbms_xplan.display(format=>'BASIC'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------
Plan hash value: 3255648551

----------------------------------------------
| Id | Operation                   | Name    |
----------------------------------------------
| 0 | SELECT STATEMENT             |         |
| 1 |  SORT AGGREGATE              |         |
| 2 |   FIRST ROW                  |         |
| 3 |    INDEX RANGE SCAN (MIN/MAX)| T1_I1   |
----------------------------------------------

INDEX SKIP SCAN

SQL> explain plan for
   2 SELECT /*+ index_ss(t1 (c1,c2)) */ * FROM t1 WHERE c2 = 3 ORDER BY c1, c2;

Explained.

SQL> select * from table(dbms_xplan.display(format=>'BASIC'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------
Plan hash value: 2886394002

---------------------------------------------
| Id | Operation                   | Name   |
---------------------------------------------
| 0  | SELECT STATEMENT            |        |
| 1  |  TABLE ACCESS BY INDEX ROWID| T1     |
| 2  |   INDEX SKIP SCAN           | T1_I1  |
---------------------------------------------

INDEX SKIP SCAN DESCENDING

SQL> explain plan for
   2 SELECT /*+ index_ss_desc(t1 (c1,c2)) */ * FROM t1 WHERE c2 = 3 ORDER BY c1 DESC, c2 DESC;

Explained.

SQL> select * from table(dbms_xplan.display(format=>'BASIC'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------
Plan hash value: 216564213

---------------------------------------------
| Id | Operation                   | Name   |
---------------------------------------------
| 0  | SELECT STATEMENT            |        |
| 1  |  TABLE ACCESS BY INDEX ROWID| T1     |
| 2  |   INDEX SKIP SCAN DESCENDING| T1_I1  |
---------------------------------------------

INDEX UNIQUE SCAN

SQL> CREATE UNIQUE INDEX t1_i2 ON t1 (c2);

Index created.

SQL> explain plan for
   2 SELECT /*+ index(t1 (c2)) */ * FROM t1 WHERE c2 = 1;

Explained.

SQL> select * from table(dbms_xplan.display(format=>'BASIC'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------
Plan hash value: 3045864492

---------------------------------------------
| Id | Operation                   | Name   |
---------------------------------------------
| 0  | SELECT STATEMENT            |        |
| 1  |  TABLE ACCESS BY INDEX ROWID| T1     |
| 2  |   INDEX UNIQUE SCAN         | T1_I2  |
---------------------------------------------

INDEX FAST FULL SCAN

SQL> explain plan for
   2 SELECT /*+ index_ffs(t1 (c1, c2)) */ c1, c2 FROM t1 WHERE c2 = 1;

Explained.

SQL> select * from table(dbms_xplan.display(format=>'BASIC'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------
Plan hash value: 986441562

--------------------------------------
| Id | Operation            | Name   |
--------------------------------------
| 0  | SELECT STATEMENT     |        |
| 1  |  INDEX FAST FULL SCAN| T1_I1  |
--------------------------------------

INDEX SAMPLE FAST FULL SCAN

SQL> explain plan for
   2 SELECT /*+ index_ffs(t1 (c1, c2)) */ c1, c2 FROM t1 SAMPLE (5);

Explained.

SQL> select * from table(dbms_xplan.display(format=>'BASIC'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------
Plan hash value: 2304923920

---------------------------------------------
| Id | Operation                   | Name   |
---------------------------------------------
| 0  | SELECT STATEMENT            |        |
| 1  |  INDEX SAMPLE FAST FULL SCAN| T1_I1  |
---------------------------------------------

HASH JOIN(INDEX JOIN)

SQL> conn hr/hr@pdb1
Connected.
SQL> explain plan for
   2 SELECT e.first_name FROM hr.employees e WHERE e.manager_id >=100 AND e.last_name LIKE '%ran%';

Explained.

SQL> select * from table(dbms_xplan.display(format=>'BASIC'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------
Plan hash value: 3059678737

---------------------------------------------------
| Id | Operation               | Name             |
---------------------------------------------------
| 0  | SELECT STATEMENT        |                  |
| 1  |  VIEW                   | index$_join$_001 |
| 2  |   HASH JOIN             |                  |
| 3  |    INDEX RANGE SCAN     | EMP_MANAGER_IX   |
| 4  |    INDEX FAST FULL SCAN | EMP_NAME_IX      |
---------------------------------------------------

AND-EQUAL

SQL> explain plan for
   2 SELECT /*+ and_equal(e (manager_id) (job_id)) */
   3 employee_id
   4 ,first_name
   5 ,last_name
   6 ,email
   7 FROM hr.employees e
   8 WHERE e.manager_id = 124 AND e.job_id = 'SH_CLERK';

Explained.

SQL> select * from table(dbms_xplan.display(format=>'BASIC'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------
Plan hash value: 2196596023

------------------------------------------------------
| Id | Operation                   | Name            |
------------------------------------------------------
| 0  | SELECT STATEMENT            |                 |
| 1  |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES       |
| 2  |   AND-EQUAL                 |                 |
| 3  |    INDEX RANGE SCAN         | EMP_MANAGER_IX  |
| 4  |    INDEX RANGE SCAN         | EMP_JOB_IX      |
------------------------------------------------------

参考資料

Expert Oracle SQL 

Expert Oracle SQL: Optimization, Deployment, and Statistics

Expert Oracle SQL: Optimization, Deployment, and Statistics

 

SQLパフォーマンス詳解

SQLパフォーマンス詳解

SQLパフォーマンス詳解

 

データベースパフォーマンスアップの教科書 基本原理編 

データベースパフォーマンスアップの教科書 基本原理編

データベースパフォーマンスアップの教科書 基本原理編

 

パフォーマンス改善と事前対策に役立つ Oracle SQLチューニング 

パフォーマンス改善と事前対策に役立つ Oracle SQLチューニングSQLチューニング (DB SELECTION)

パフォーマンス改善と事前対策に役立つ Oracle SQLチューニングSQLチューニング (DB SELECTION)

 

プログラマのためのSQL 第4版 すべてを知り尽くしたいあなたに

プログラマのためのSQL 第4版

プログラマのためのSQL 第4版

 

SQL実践入門──高速でわかりやすいクエリの書き方 

SQL実践入門──高速でわかりやすいクエリの書き方 (WEB+DB PRESS plus)

SQL実践入門──高速でわかりやすいクエリの書き方 (WEB+DB PRESS plus)

 

Oracle EVENT 10053(CBOトレース)の出力例

概要

Oracleの10053(CBO)トレースを読み解く際の確認すべきセクションを記載します。

各セクション

ヘッダー(Oracle/OS/ロケーション/CPU/メモリ)
Trace file /opt/oracle/diag/rdbms/ora12201/ora12201/trace/ora12201_ora_9374.trc
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
Build label: RDBMS_12.2.0.1.0_LINUX.X64_170125
ORACLE_HOME: /opt/oracle/product/12.2.0.1/dbhome_1
System name: Linux
Node name: b4eb3c10ed7d
Release: 3.10.0-862.2.3.el7.x86_64
Version: #1 SMP Wed May 9 18:05:47 UTC 2018
Machine: x86_64
Instance name: ora12201
Redo thread mounted by this instance: 1
Oracle process number: 40
Unix process pid: 9374, image: oracle@b4eb3c10ed7d
セッション情報(セッションID/MODULE/ACTION)
*** 2018-05-28T13:43:50.210067+00:00 (PDB1(3))
*** SESSION ID:(21.61083) 2018-05-28T13:43:50.210095+00:00
*** CLIENT ID:() 2018-05-28T13:43:50.210108+00:00
*** SERVICE NAME:(pdb1) 2018-05-28T13:43:50.210112+00:00
*** MODULE NAME:(SQL*Plus) 2018-05-28T13:43:50.210115+00:00
*** ACTION NAME:() 2018-05-28T13:43:50.210119+00:00
*** CLIENT DRIVER:(SQL*PLUS) 2018-05-28T13:43:50.210172+00:00
*** CONTAINER ID:(3) 2018-05-28T13:43:50.210179+00:00
クエリブロックとエイリアス
Registered qb: SEL$1 0xf54998a0 (PARSER)
---------------------
QUERY BLOCK SIGNATURE
---------------------
   signature (): qb_name=SEL$1 nbfros=1 flg=0
    fro(0): flg=4 objn=73825 hint_alias="EMPLOYEES"@"SEL$1"Registered qb: SEL$2 0xf5490e00 (PARSER)
---------------------
QUERY BLOCK SIGNATURE
---------------------
   signature (): qb_name=SEL$2 nbfros=1 flg=0
   fro(0): flg=4 objn=73825 hint_alias="EMPLOYEES"@"SEL$2"
SPM: statement not found in SMB
SPM: capture of plan baseline is OFF

qbはQUERY BLOCK(問合せブロック)の略です。今回の出力内容では2つのクエリブロック(SEL$1/SEL$2)が出力されています。
共にEMPLOYEESテーブルで同一オブジェクト(objn=73825)ですが、主問合せとサブクエリのクエリブロックが分かれている形になります。
なお、下部のSPMのメッセージはSQL計画管理(SPM)です。

ADOP(自動並列度)
**************************
Automatic degree of parallelism (AUTODOP)
**************************
Automatic degree of parallelism is disabled: Parameter.
kkopqSetForceParallelProperties: Hint:no
Query: compute:yes forced:no forceDop:0
Global Manual Dop: 1 - Rounded?: no

上記例ではADOPが機能していないことを表しています。

述語移動
PM: Considering predicate move-around in query block SEL$1 (#0)
**************************
Predicate Move-Around (PM)
**************************
OPTIMIZER INFORMATION

predicate(述語)とは問合せ条件の単位です。
問合せ変換(最適化)として、A表とB表のJOINをする場合にA表に指定された条件がB表にも適用可能な時にはCBOはB表にも同じ条件を追加することで、JOINの対象行を減らすという最適化を試行します。
今回は、出力の最後が「(#0)」つまり0件となっているので、試行したが対象は存在しなかったということを表しています。

解析対象のSQL文の表示
----- Current SQL Statement for this session (sql_id=43s9nuk0zjx4w) -----
select
    /*+ hard parse */
    first_name,
    last_name,
    hire_Date
from
    employees
where
    hire_date in(
        select
            hire_date
        from
            employees
        where
            department_id = 30
)
トレース内の略語リストと説明
Legend
The following abbreviations are used by optimizer trace.
CBQT - cost-based query transformation
JPPD - join predicate push-down
OJPPD - old-style (non-cost-based) JPPD
FPD - filter push-down
PM - predicate move-around
CVM - complex view merging
SPJ - select-project-join
SJC - set join conversion
SU - subquery unnesting
OBYE - order by elimination
OST - old style star transformation
ST - new (cbqt) star transformation
CNT - count(col) to count(*) transformation
JE - Join Elimination
JF - join factorization
CBY - connect by
SLP - select list pruning
DP - distinct placement
VT - vector transformation
AAT - Approximate Aggregate Transformation
ORE - CBQT OR-Expansion
LORE - Legacy OR-Expansion
qb - query block
LB - leaf blocks
DK - distinct keys
LB/K - average number of leaf blocks per key
DB/K - average number of data blocks per key
CLUF - clustering factor
NDV - number of distinct values
Resp - response cost
Card - cardinality
Resc - resource cost
NL - nested loops (join)
SM - sort merge (join)
HA - hash (join)
CPUSPEED - CPU Speed
IOTFRSPEED - I/O transfer speed
IOSEEKTIM - I/O seek time
SREADTIM - average single block read time
MREADTIM - average multiblock read time
MBRC - average multiblock read count
MAXTHR - maximum I/O system throughput
SLAVETHR - average slave I/O throughput
dmeth - distribution method
  1: no partitioning required
  2: value partitioned
  4: right is random (round-robin)
  128: left is random (round-robin)
  8: broadcast right and partition left
  16: broadcast left and partition right
  32: partition left using partitioning of right
  64: partition right using partitioning of left
  256: run the join in serial
  0: invalid distribution method
sel - selectivity
ptn - partition
AP - adaptive plans

これらの情報は、先述の「Predicate Move-Around (PM)」を確認する際に使用します。

パラメータのリスト(変更済/デフォルト/ヒント)
***************************************
PARAMETERS USED BY THE OPTIMIZER
********************************
  *************************************
  PARAMETERS WITH ALTERED VALUES
  ******************************
  :
  *************************************
  PARAMETERS WITH DEFAULT VALUES
  ******************************
Compilation Environment Dump
optimizer_mode_hinted = false
optimizer_features_hinted = 0.0.0
parallel_execution_enabled = true
parallel_query_forced_dop = 0
:
(中略)
:
  ***************************************
  PARAMETERS IN OPT_PARAM HINT
  ****************************

オプティマイザの動作に関するパラメータの一覧です。※全て出力されるわけではありません。

クエリブロックの変換
Considering Query Transformations on query block SEL$1 (#0)
**************************
Query transformations (QT)
**************************
JF: Checking validity of join factorization for query block SEL$2 (#0)
JF: Bypassed: not a UNION or UNION-ALL query block.
ST: not valid since star transformation parameter is FALSE
TE: Checking validity of table expansion for query block SEL$2 (#0)
TE: Bypassed: No partitioned table in query block.
ORE: Checking validity of OR Expansion for query block SEL$2 (#0)
ORE: Predicate chain before QB validity check - SEL$2
"EMPLOYEES"."DEPARTMENT_ID"=30
ORE: Predicate chain after QB validity check - SEL$2
"EMPLOYEES"."DEPARTMENT_ID"=30
ORE: bypassed - No valid predicate for OR expansion.
VT: Initial VT validity check for query block SEL$2 (#0)
VT: Bypassed: inmemory is disabled.
BJ: Checking validity for bushy join for query block SEL$2 (#0)
invalid because Not enabled by hint/parameter
BJ: Bypassed: Not enabled by hint/parameter.
CBQT: Validity checks passed for 43s9nuk0zjx4w.
CSE: Considering common sub-expression elimination in query block SEL$1 (#0)
:
バインド・ピークに関する情報
*******************************************
Peeked values of the binds in SQL statement
*******************************************

今回はバインド変数を使用していないので特に出力はありません。

問合せ変換(最適化)後のSQL
*************************
Common Subexpression elimination (CSE)
*************************
CSE: CSE not performed on query block SEL$5DA710D3 (#1).
Final query after transformations:******* UNPARSED QUERY IS *******
SELECT "EMPLOYEES"."FIRST_NAME" "FIRST_NAME","EMPLOYEES"."LAST_NAME" "LAST_NAME","EMPLOYEES"."HIRE_DATE" "HIRE_DATE" FROM "HR"."EMPLOYEES" "EMPLOYEES","HR"."EMPLOYEES" "EMPLOYEES" WHERE "EMPLOYEES"."HIRE_DATE"="EMPLOYEES"."HIRE_DATE" AND "EMPLOYEES"."DEPARTMENT_ID"=30
kkoqbc: optimizing query block SEL$5DA710D3 (#1)

      :
    call(in-use=4392, alloc=16344), compile(in-use=179064, alloc=183040), execution(in-use=3200, alloc=4032)
実行SQL

  select
      /*+ hard parse */
      first_name,
      last_name,
      hire_Date
   from
      employees
      where
      hire_date in(
         select
                      hire_date
                  from
              employees
         where
             department_id = 30
       )
   ;

変換後SQL

  SELECT
           "EMPLOYEES"."FIRST_NAME" "FIRST_NAME",
           "EMPLOYEES"."LAST_NAME" "LAST_NAME",
           "EMPLOYEES"."HIRE_DATE" "HIRE_DATE"
  FROM
           "HR"."EMPLOYEES" "EMPLOYEES",
           "HR"."EMPLOYEES" "EMPLOYEES"
  WHERE
          "EMPLOYEES"."HIRE_DATE" = "EMPLOYEES"."HIRE_DATE"
  AND "EMPLOYEES"."DEPARTMENT_ID" = 30

システム統計に関する表示
-----------------------------
SYSTEM STATISTICS INFORMATION
-----------------------------
  Using dictionary system stats.
  Using NOWORKLOAD Stats
  CPUSPEEDNW: 2923 millions instructions/sec (default is 100)
  IOTFRSPEED: 4096 bytes per millisecond (default is 4096)
  IOSEEKTIM: 10 milliseconds (default is 10)
  MBRC: NO VALUE blocks (default is 8)
  • CPUSPEEDNW:CPU速度(MHz)
  • IOSEEKTIM:シークタイム + OSオーバーヘッドの時間(ミリ秒)
  • IOTFRSPEED:1ブロックの平均転送速度(bytes/millisec)
  • MBRC:マルチブロックI/O時の読み込みブロック数の平均
オブジェクト統計
***************************************
BASE STATISTICAL INFORMATION
***********************
Table Stats::
  Table: EMPLOYEES Alias: EMPLOYEES
  #Rows: 107 SSZ: 0 LGR: 0 #Blks: 5 AvgRowLen: 69.00 NEB: 0 ChainCnt: 0.00 ScanRate: 0.00 SPC: 0 RFL: 0 RNF: 0 CBK: 0 CHR: 0 KQDFLG: 1
  #IMCUs: 0 IMCRowCnt: 0 IMCJournalRowCnt: 0 #IMCBlocks: 0 IMCQuotient: 0.000000
  Column (#6): HIRE_DATE(DATE)
    AvgLen: 8 NDV: 98 Nulls: 0 Density: 0.010204 Min: 2451923.000000 Max: 2454578.000000
Index Stats::
  Index: EMP_DEPARTMENT_IX Col#: 11
LVLS: 0 #LB: 1 #DK: 11 LB/K: 1.00 DB/K: 1.00 CLUF: 7.00 NRW: 106.00 SSZ: 0.00 LGR: 0.00 CBK: 0.00 GQL: 0.00 CHR: 0.00 KQDFLG: 8192 BSZ: 1
KKEISFLG: 1
  Index: EMP_EMAIL_UK Col#: 4
LVLS: 0 #LB: 1 #DK: 107 LB/K: 1.00 DB/K: 1.00 CLUF: 19.00 NRW: 107.00 SSZ: 0.00 LGR: 0.00 CBK: 0.00 GQL: 0.00 CHR: 0.00 KQDFLG: 8192 BSZ: 1
KKEISFLG: 1
  Index: EMP_EMP_ID_PK Col#: 1
LVLS: 0 #LB: 1 #DK: 107 LB/K: 1.00 DB/K: 1.00 CLUF: 2.00 NRW: 107.00 SSZ: 0.00 LGR: 0.00 CBK: 0.00 GQL: 0.00 CHR: 0.00 KQDFLG: 8192 BSZ: 1
KKEISFLG: 1
  Index: EMP_JOB_IX Col#: 7
LVLS: 0 #LB: 1 #DK: 19 LB/K: 1.00 DB/K: 1.00 CLUF: 8.00 NRW: 107.00 SSZ: 0.00 LGR: 0.00 CBK: 0.00 GQL: 0.00 CHR: 0.00 KQDFLG: 8192 BSZ: 1
KKEISFLG: 1
  Index: EMP_MANAGER_IX Col#: 10
LVLS: 0 #LB: 1 #DK: 18 LB/K: 1.00 DB/K: 1.00 CLUF: 7.00 NRW: 106.00 SSZ: 0.00 LGR: 0.00 CBK: 0.00 GQL: 0.00 CHR: 0.00 KQDFLG: 8192 BSZ: 1
KKEISFLG: 1
  Index: EMP_NAME_IX Col#: 3 2
LVLS: 0 #LB: 1 #DK: 107 LB/K: 1.00 DB/K: 1.00 CLUF: 15.00 NRW: 107.00 SSZ: 0.00 LGR: 0.00 CBK: 0.00 GQL: 0.00 CHR: 0.00 KQDFLG: 8192 BSZ: 1
KKEISFLG: 1
:

Table Stats::

  • Table:テーブル名
  • Alias:テーブルの別名
  • #Rows:行数
  • #Blks:HWMまでのブロック数
  • AvgRowLen:平均行長
  • ChainCnt:行連鎖の数
  • Column (列番号): 列名(属性)
  • AvgLen:平均列長
  • NDV:ユニークな値の数
  • Nulls:NULL値の数
  • Density:列の密度
  • Min:列の最小値
  • Max:列の最大値

Index Stats::

  • Index:索引名
  • Col#:列番号
  • LVLS:索引の高さ
  • #LB:リーフ・ブロック数
  • #DK:キー値の種類(DISTINCT_KEYS)
  • LB/K:1つのキー値に占めるリーフ・ブロック数
  • DB/K:1つのキー値が参照している表のブロック数
  • CLUF:クラスタ化係数
テーブルアクセスパスの解析情報
Access path analysis for EMPLOYEES
***************************************
SINGLE TABLE ACCESS PATH
  Single Table Cardinality Estimation for EMPLOYEES[EMPLOYEES]
  SPD: Return code in qosdDSDirSetup: NOCTX, estType = TABLE
 kkecdn: Single Table Predicate:"EMPLOYEES"."DEPARTMENT_ID"=30
  Column (#11):
    NewDensity:0.004717, OldDensity:0.004717 BktCnt:106.000000, PopBktCnt:103.000000, PopValCnt:8, NDV:11
  Column (#11): DEPARTMENT_ID(NUMBER)
    AvgLen: 3 NDV: 11 Nulls: 1 Density: 0.004717 Min: 10.000000 Max: 110.000000
    Histogram: Freq #Bkts: 11 UncompBkts: 106 EndPtVals: 11 ActualVal: yes
  Estimated selectivity: 0.056604 , endpoint value predicate, col: #11
  Table: EMPLOYEES Alias: EMPLOYEES
    Card: Original: 107.000000 Rounded: 6 Computed: 6.000000 Non Adjusted: 6.000000
  Scan IO Cost (Disk) = 3.000000
  Scan CPU Cost (Disk) = 73057.200000
  Cost of predicates:
    io = NOCOST, cpu = 50.000000, sel = 0.056604 flag = 2048 ("EMPLOYEES"."DEPARTMENT_ID"=30)
  Total Scan IO Cost =   3.000000 (scan (Disk))
                       + 0.000000 (io filter eval) (= 0.000000 (per row) * 107.000000 (#rows))
                     =   3.000000
  Total Scan CPU Cost =  73057.200000 (scan (Disk))
                       + 5350.000000 (cpu filter eval) (= 50.000000 (per row) * 107.000000 (#rows))
                      =  78407.200000
  Access Path: TableScan
    Cost: 3.002235 Resp: 3.002235 Degree: 0
      Cost_io: 3.000000 Cost_cpu: 78407
      Resp_io: 3.000000 Resp_cpu: 78407
  ****** Costing Index EMP_DEPARTMENT_IX
  SPD: Return code in qosdDSDirSetup: NOCTX, estType = INDEX_SCAN
  SPD: Return code in qosdDSDirSetup: NOCTX, estType = INDEX_FILTER
  Estimated selectivity: 0.056604 , endpoint value predicate, col: #11
  Access Path: index (AllEqRange)
    Index: EMP_DEPARTMENT_IX
    resc_io: 2.000000 resc_cpu: 17543
    ix_sel: 0.056604 ix_sel_with_filters: 0.056604
    Cost: 2.000500 Resp: 2.000500 Degree: 1
  Best:: AccessPath: IndexRange
  Index: EMP_DEPARTMENT_IX
         Cost: 2.000500 Degree: 1 Resp: 2.000500 Card: 6.000000 Bytes: 0.000000
:

上記の出力内容からTableScanコスト(3.002235)とindex scanのコスト(2.000500)を比較し、コストの低いindex scanがBestAccessPathとして選択されています。

可能な結合方法の解析
OPTIMIZER STATISTICS AND COMPUTATIONS
***************************************
GENERAL PLANS
***************************************
Considering cardinality-based initial join order.
Permutations for Starting Table :0
Join order[1]: EMPLOYEES[EMPLOYEES]#0 EMPLOYEES[EMPLOYEES]#1
***************
Now joining: EMPLOYEES[EMPLOYEES]#1
***************
NL Join
  Outer table: Card: 107.000000 Cost: 3.001778 Resp: 3.001778 Degree: 1 Bytes:
Access path analysis for EMPLOYEES
  Scan IO Cost (Disk) = 1.373832
  Scan CPU Cost (Disk) = 73057.200000
  Cost of predicates:
    io = NOCOST, cpu = 50.000000, sel = 0.010204 flag = 2048 ("EMPLOYEES"."HIRE_DATE"="EMPLOYEES"."HIRE_DATE")
    io = NOCOST, cpu = 50.000000, sel = 0.056604 flag = 2064 ("EMPLOYEES"."DEPARTMENT_ID"=30)
  Total Scan IO Cost = 1.373832 (scan (Disk))
                     + 0.000000 (io filter eval) (= 0.000000 (per row) * 107.000000 (#rows))
                     = 1.373832
  Total Scan CPU Cost = 73057.200000 (scan (Disk))
                      + 5404.591837 (cpu filter eval) (= 50.510204 (per row) * 107.000000 (#rows))
                      = 78461.791837
  Inner table: EMPLOYEES Alias: EMPLOYEES
  Access Path: TableScan
    NL Join: Cost: 150.241105 Resp: 150.241105 Degree: 1
      Cost_io: 150.000000 Cost_cpu: 8457769
      Resp_io: 150.000000 Resp_cpu: 8457769
:
(中略)
:
Final cost for query block SEL$5DA710D3 (#1) - All Rows Plan:
  Best join order: 1
  Cost: 5.019856 Degree: 1 Card: 7.000000 Bytes: 238.000000
  Resc: 5.019856 Resc_io: 5.000000 Resc_cpu: 696550
  Resp: 5.019856 Resp_io: 5.000000 Resc_cpu: 696550
kkoqbc-subheap (delete addr=0x7fc0f549fb78, in-use=55888, alloc=65704)
kkoqbc-end:
        :
      call(in-use=17592, alloc=98600), compile(in-use=202344, alloc=202840), execution(in-use=3200, alloc=4032)
  • Best join order:選択された結合順序
  • Cost:選択された実行計画のコスト
  • Degree:並列度
  • Card:最終的に処理される行数(カーディナリティ)の見積もり
  • Resc:シリアル実行のコスト
  • Resp:パラレル実行のコスト
最終的に選択された実行計画

============
Plan Table
============
------------------------------------------------------------------+-----------------------------------+
| Id  | Operation                              | Name             | Rows  | Bytes | Cost  | Time      |
------------------------------------------------------------------+-----------------------------------+
| 0   | SELECT STATEMENT                       |                  |       |        |    5 |           |
| 1   |  HASH JOIN SEMI                        |                  |     7 |    238 |    5 |  00:00:01 |
| 2   |   NESTED LOOPS SEMI                    |                  |     7 |    238 |    5 |  00:00:01 |
| 3   |    STATISTICS COLLECTOR                |                  |       |        |      |           |
| 4   |     TABLE ACCESS FULL                  | EMPLOYEES        |   107 |   2461 |    3 |  00:00:01 |
| 5   |    TABLE ACCESS BY INDEX ROWID BATCHED | EMPLOYEES        |     1 |     11 |    2 |  00:00:01 |
| 6   |     INDEX RANGE SCAN                   | EMP_DEPARTMENT_IX|     6 |        |    1 |  00:00:01 |
| 7   |    TABLE ACCESS BY INDEX ROWID BATCHED | EMPLOYEES        |     6 |     66 |    2 |  00:00:01 |
| 8   |     INDEX RANGE SCAN                   | EMP_DEPARTMENT_IX|     6 |        |    1 |  00:00:01 |
------------------------------------------------------------------+-----------------------------------+

参考資料

Cost-Based Oracle Fundamentals

Cost-Based Oracle Fundamentals (Expert's Voice in Oracle)

Cost-Based Oracle Fundamentals (Expert's Voice in Oracle)

 

Secrets of the Oracle Database 

Secrets of the Oracle Database (Expert's Voice in Oracle)

Secrets of the Oracle Database (Expert's Voice in Oracle)

 

Expert Oracle Practices

Expert Oracle Practices: Oracle Database Administration from the Oak Table

Expert Oracle Practices: Oracle Database Administration from the Oak Table

  • 作者: Pete Finnigan,Alex Gorbachev,Tim Gorman,Charles Hooper,Jonathan Lewis,Niall Litchfield,Robyn Sands,Joze Senegacnik,Riyaj Shamsudeen,Jeremiah Wilton,Graham Wood,Connie Green,Karen Morton,Randolf Geist,Uri Shaft,Melanie Caffrey,Andrew Morton,Tom Green,Paul Wilton,Joe Lewis
  • 出版社/メーカー: Apress
  • 発売日: 2010/01/20
  • メディア: ペーパーバック
  • この商品を含むブログを見る
 

Oracle SQL Tuning with Oracle SQLTXPLAIN: Oracle Database 12c Edition, Second Edition

Oracle SQL Tuning with Oracle SQLTXPLAIN: Oracle Database 12c Edition

Oracle SQL Tuning with Oracle SQLTXPLAIN: Oracle Database 12c Edition

 

Expert Oracle RAC 12c

Expert Oracle RAC 12c (The Expert's Voice)

Expert Oracle RAC 12c (The Expert's Voice)

  • 作者: Riyaj Shamsudeen,Syed Jaffar Hussain,Kai Yu,Tariq Farooq
  • 出版社/メーカー: Apress
  • 発売日: 2013/08/19
  • メディア: ペーパーバック
  • クリック: 1回
  • この商品を含むブログを見る
 

http://www.centrexcc.com/A%20Look%20under%20the%20Hood%20of%20CBO%20-%20the%2010053%20Event.pdf

スポンサーリンク