53
Copyright © 2017 CO-Sol Inc. All Rights Reserved. 1 Copyright © 2017 CO-Sol Inc. All Rights Reserved. 2017年9月7日 株式会社コーソル 渡部 亮太 Oracle入門セミナー 実行計画を読んでみよう!

Oracleの実行計画を読んでみよう! #dbts2017

Embed Size (px)

Citation preview

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 1Copyright © 2017 CO-Sol Inc. All Rights Reserved.

2017年9月7日株式会社コーソル 渡部 亮太

Oracle入門セミナー実行計画を読んでみよう!

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 2

自己紹介+所属会社紹介

• 渡部 亮太(わたべ りょうた)

– JPOUG 共同創設者、ボードメンバー

– 日本に8名しかいないOracle ACEの一人

– 著書「Oracleの基本」9月22日発売!「プロとしてのOracleアーキテクチャ入門[第2版]」

– ブログ「コーソルDatabaseエンジニアのBlog」http://cosol.jp/techdb/

• 株式会社コーソル

– 「CO-Solutions=共に解決する」の理念のもと、Oracle技術に特化した事業を展開中。心あるサービスの提供とデータベースエンジニアの育成に注力している

– 社員数: 132名 (2017年9月時点)

– ORACLE MASTER Platinum 11g 取得者数 49名ORACLE MASTER Platinum 12c 取得者数 35名取得者数 日本 No.1 (おそらくWorld WideでNo.1)

http://www.oracle.com/jp/education/omdata-171891-ja.html

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 3

技術者育成の取り組み [コーソル紹介]

ORACLE MASTER Platinum取得者数 国内No1!

充実した教育+支援制度で技術者育成に力を入れています!

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 4

製品サービス

弊社ソリューションについて [コーソル紹介]

独自のサービスと製品を掛け合わせ、データベースの運用を強力に支援致します。

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 5

[宣伝・告知] DB移行セミナーやります

• 9月13日(水) 19:00-20:30

• https://connpass.com/event/63720/

• 技術領域: Oracle Database / Attunity

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 6

本セミナーについて

• 比較的シンプルなSQLの実行計画を題材にして、Oracle Databaseの実行計画の読み方を学びます

• Oracle Database初級者~中級者向けのセミナーです。が、純粋な講義形式にしても眠くなるだけ :-P なので、すこし対話形式のエッセンスを入れながら進めたいと思います

• 途中で、実行計画を読むにあたって、落とし穴になりがちな点についても説明します

• 質問は随時Welcomeです。質疑応答が盛り上がったほうが、みんなの理解が深まるはず!

• 読みやすさ・理解しやすさのため、掲載するSQLや実行計画は実際のもの から適宜 加工・修正しています

• 同様の理由で、記述・説明の網羅性を犠牲にしているため、キチンと理解したい場合は、マニュアルを参照してください

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 7

Agenda

• 実行計画とは

• 実行計画の取得方法 (見積ベース or 過去の実行)

• ツリー構造のたどり方(実行計画の実行順序)

• 基本的なオペレーションを理解する

• 処理の流れをイメージできるようにする

• 統計値の解釈(見積値 or 実測値、累積、 starts)

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 8Copyright © 2017 CO-Sol Inc. All Rights Reserved.

実行計画とは

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 9

実行計画とは

• 実行計画は、SQLがOracleで実行される手順を示す• 実行計画はコストベースオプティマイザ(CBO; Cost-

Based Optimizer)が作成する– CBOはOracleの内部コンポーネント– オプティマイザ統計が最新でないと適切な実行計画が作成され

ないことに注意

• 不適切な実行計画でSQLが実行されると、本来であれば実現できる処理パフォーマンスを得られない

---------------------------------------------------------------------| Id | Operation | Name | Rows |...| Time |---------------------------------------------------------------------| 0 | SELECT STATEMENT | | |...| || 1 | TABLE ACCESS BY INDEX ROWID| TAB0 | 16 |...| 00:00:01 ||* 2 | INDEX RANGE SCAN | T0_IDX | 16 |...| 00:00:01 |---------------------------------------------------------------------

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 10

実行計画に含まれる情報

PLAN_TABLE_OUTPUT--------------------------------------------------------------------------------------SQL_ID 3hrvf65nm048d, child number 0-------------------------------------SELECT * from tab0 WHERE col_idx = 'A'

Plan hash value: 2195618789

--------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 7 (100)| || 1 | TABLE ACCESS BY INDEX ROWID| TAB0 | 16 | 32160 | 7 (0)| 00:00:01 ||* 2 | INDEX RANGE SCAN | T0_IDX | 16 | | 1 (0)| 00:00:01 |--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - access("COL_IDX"='A')

ツリー構造をしたステップ 各ステップの統計値

補足情報

ステップ実行計画の実行手順における実行要素親子関係がある

←SQL文

sql_id: SQL文の識別子(Oracleが自動的に付与)

←実行計画のハッシュ値

※:取得方法によって、情報が表示される/されないが異なる点に注意

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 11

実行計画の確認方法

確認方法 実行計画

統計値

備考

a EXPLAIN PLAN +DBMS_XPLAN.DISPLAY

見積 見積 SQLは実行されない

b SQL実行 →DBMS_XPLAN.DISPLAY_CURSOR

実行 見積

c STATISTICS_LEVEL=ALLでSQL実行 → DBMS_XPLAN.DISPLAY_CURSOR(format=>'ALLSTATS LAST')

実行 見積実行

見積統計と実行統計の両方を表示

• 実行計画の正確性の観点から、 DBMS_XPLAN.DISPLAY_CURSORを使う方法(b,c)がオススメ– 共有プール(キャッシュ領域)から実行計画および統計値を取得

• EXPLAN PLAN(a)もお手軽で便利!だけど、参考用途に

見積: Oracleが見積もった(予測した)実行計画または統計値を表示実行: 過去のSQL実行で実際に使われた実行計画または統計値を表示

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 12

a) EXPLAIN PLAN + DBMS_XPLAN.DISPLAY

SQL> EXPLAIN PLAN FOR SELECT * FROM tab0 WHERE col_idx = 'A';

解析されました。

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

PLAN_TABLE_OUTPUT----------------------------------------------------------------------------------------------------Plan hash value: 2195618789

--------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 16 | 32160 | 7 (0)| 00:00:01 || 1 | TABLE ACCESS BY INDEX ROWID| TAB0 | 16 | 32160 | 7 (0)| 00:00:01 ||* 2 | INDEX RANGE SCAN | T0_IDX | 16 | | 1 (0)| 00:00:01 |--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - access("COL_IDX"='A')

14行が選択されました。

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 13

b) SQL実行 → DBMS_XPLAN.DISPLAY_CURSOR

SQL> set serveroutput offSQL> SELECT * from tab0 WHERE col_idx = 'A';(略)SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR);

PLAN_TABLE_OUTPUT---------------------------------------------------------------------------------------------------SQL_ID 3hrvf65nm048d, child number 0-------------------------------------SELECT * from tab0 WHERE col_idx = 'A'

Plan hash value: 2195618789

--------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 7 (100)| || 1 | TABLE ACCESS BY INDEX ROWID| TAB0 | 16 | 32160 | 7 (0)| 00:00:01 ||* 2 | INDEX RANGE SCAN | T0_IDX | 16 | | 1 (0)| 00:00:01 |--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - access("COL_IDX"='A')

19行が選択されました。

sql_idの指定を省略すると直近実行したSQLの実行計画を表示ただし set serveroutput onだとうまく動かないことに注意

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 14

c) DBMS_XPLAN.DISPLAY_CURSOR(format=>'ALLSTATS LAST')

SQL> set serveroutput offSQL> ALTER SESSION SET statistics_level=ALL;SQL> SELECT * from tab0 WHERE col_idx = 'A';(略)SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=>'ALLSTATS LAST'))

PLAN_TABLE_OUTPUT---------------------------------------------------------------------------------------------------SQL_ID 3hrvf65nm048d, child number 0-------------------------------------SELECT * from tab0 WHERE col_idx = 'A'

Plan hash value: 2195618789

------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 16 |00:00:00.01 | 10 || 1 | TABLE ACCESS BY INDEX ROWID| TAB0 | 1 | 16 | 16 |00:00:00.01 | 10 ||* 2 | INDEX RANGE SCAN | T0_IDX | 1 | 16 | 16 |00:00:00.01 | 3 |------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - access("COL_IDX"='A')

19行が選択されました。

LASTを指定しないと複数実行の平均値になることに注意

実行統計(A-xxx:Actual)が表示される※: ここではE-Rowsのみが見積統計

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 15Copyright © 2017 CO-Sol Inc. All Rights Reserved.

単一テーブルアクセスのオペレーション

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 16

オペレーションとは

PLAN_TABLE_OUTPUT--------------------------------------------------------------------------------------SQL_ID 3hrvf65nm048d, child number 0-------------------------------------SELECT * from tab0 WHERE col_idx = 'A'

Plan hash value: 2195618789

--------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 7 (100)| || 1 | TABLE ACCESS BY INDEX ROWID| TAB0 | 16 | 32160 | 7 (0)| 00:00:01 ||* 2 | INDEX RANGE SCAN | T0_IDX | 16 | | 1 (0)| 00:00:01 |--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - access("COL_IDX"='A')

オペレーション各ステップで実行される操作の種類TABLE ACCESS FULL、 INDEX RANGE SCAN など

ステップ実行計画の実行手順における実行要素親子関係がある

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 17

テーブルフルスキャン

select * from tab0 where col_noix = 'A'

--------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 9 (100)| ||* 1 | TABLE ACCESS FULL| TAB0 | 16 | 32160 | 9 (0)| 00:00:01 |--------------------------------------------------------------------------

1 - filter("COL_NOIX"='A')

TABLE ACCESS FULL

filter

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 18

インデックス経由のテーブルアクセス(一意)

select * from tab0 where id = '1';

---------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |---------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 1 (100)| || 1 | TABLE ACCESS BY INDEX ROWID| TAB0 | 1 | 2010 | 1 (0)| 00:00:01 ||* 2 | INDEX UNIQUE SCAN | PK_TAB0 | 1 | | 0 (0)| |---------------------------------------------------------------------------------------

2 - access("ID"=1)

INDEX UNIQUE SCAN

TABLE ACCESS BY INDEX ROWID

access

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 19

インデックス経由のテーブルアクセス(範囲)

select * from tab0 where col_idx = 'A';

------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 7 (100)| || 1 | TABLE ACCESS BY INDEX ROWID| TAB0 | 16 | 32160 | 7 (0)| 00:00:01 ||* 2 | INDEX RANGE SCAN | IDX0 | 16 | | 1 (0)| 00:00:01 |------------------------------------------------------------------------------------

2 - access("COL_IDX1"='A')

INDEX RANGE SCAN

TABLE ACCESS BY INDEX ROWID

access

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 20Copyright © 2017 CO-Sol Inc. All Rights Reserved.

実行計画のツリー構造

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 21

実行計画のツリー構造

----------------------------------| Id | Operation | Name |----------------------------------| 0 | SELECT STATEMENT | ||* 1 | TABLE ACCESS FULL| TAB0 |----------------------------------

オペレーション各ステップで実行される操作の種類[オペレーションの例]TABLE ACCESS FULLINDEX RANGE SCAN

ステップ実行計画の実行手順における実行要素親子関係がある

ステップの親子関係親は子から「行」を受け取る2つ以上の子ステップを持つことがある(オペレーションの種類による)

0: SEL 1: TAF

Rows

親 子

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 22

ツリー構造のたどり方

• インデントが深いところから見てゆく(実行開始する)んだろうなぁ・・・という認識はあるかと思いますが・・・

• [問題] 以下の実行計画で、(実質的に)最初に実行されるステップはどれでしょう?

----------------------------------------------------| Id | Operation | Name |----------------------------------------------------| 0 | SELECT STATEMENT | || 1 | NESTED LOOPS | ||* 2 | TABLE ACCESS FULL | PA || 3 | TABLE ACCESS BY INDEX ROWID | CH ||* 4 | INDEX RANGE SCAN | IDX_CHPA |----------------------------------------------------

a

b

c

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 23

ツリー構造を整理

-------------------------------------------------| Id | Operation | Name |-------------------------------------------------| 0 | SELECT STATEMENT | || 1 | NESTED LOOPS | ||* 2 | TABLE ACCESS FULL | PA || 3 | TABLE ACCESS BY INDEX ROWID| CH ||* 4 | INDEX RANGE SCAN | IDX_CHPA |-------------------------------------------------

0: SEL 1: NL

2: TAF

3: TAIR 4: IRS

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 24

ツリー構造のたどり方

0: SEL 1: NL

2: TAF

3: TAIR 4: IRS

1. 最上位から親→子方向にたどってゆく

2. 複数の「子ステップ」がある場合、表形式表示で上にある「子ステップ」に進む

3. そのステップから、さらに親→子方向にたどってゆく

4. 最下位の「子ステップ」に到達したら、実行を開始する。

5. 実行終了したら、「親ステップ」に戻る

6. その「親ステップ」に、他の「子ステップ」がある場合、表形式表示で上にある「子ステップ」に進み、3. へない場合、その「親ステップ」を実行し、その「親ステップ」の「さらに親のステップ」に戻り、6.を繰り返す

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 25

ツリー構造のたどり方

0: SEL 1: NL

2: TAF

3: TAIR 4: IRS

1. 最上位から親→子方向にたどってゆく

2. 複数の「子ステップ」がある場合、表形式表示で上にある「子ステップ」に進む

3. そのステップから、さらに親→子方向にたどってゆく

4. 最下位の「子ステップ」に到達したら、実行を開始する。

5. 実行終了したら、「親ステップ」に戻る

6. その「親ステップ」に、他の「子ステップ」がある場合、表形式表示で上にある「子ステップ」に進み、3. へない場合、その「親ステップ」を実行し、その「親ステップ」の「さらに親のステップ」に戻り、6.を繰り返す

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 26

というわけで正解は

• かならずしも、最も深いインデントのステップから実行されるわけではないことに注意– きちんとした説明が面倒だからか・・・ 誤った情報が結構流布されている

-------------------------------------------------| Id | Operation | Name |-------------------------------------------------| 0 | SELECT STATEMENT | || 1 | NESTED LOOPS | ||* 2 | TABLE ACCESS FULL | PA || 3 | TABLE ACCESS BY INDEX ROWID| CH ||* 4 | INDEX RANGE SCAN | IDX_CHPA |-------------------------------------------------

0: SEL 1: NL

2: TAF

3: TAIR 4: IRS

最初に実行

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 27Copyright © 2017 CO-Sol Inc. All Rights Reserved.

テーブルの結合と実行計画

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 28

結合とは

EMPNO ENAME … DEPTNO

1001 本山三郎 2

1002 中村次郎 2

1003 山田花子 1

1004 三田海子 3

1005 山本太郎 1

1006 山田一朗 1

DEPTNO DNAME TELNO

1 金融部 0312345678

2 流通部 0312345679

3 公共部 0312345670

4 特別部 0312345677

EMPNO ENAME DNAME

1001 本山三郎 流通部

1002 中村次郎 流通部

1003 山田花子 金融部

1004 三田海子 公共部

1005 山本太郎 金融部

1006 山田一朗 金融部

[結合条件]emp.deptno = dept.deptno

empテーブル(従業員)

deptテーブル(部署)

[SQL]SELECT empno, ename, dname

FROM emp JOIN deptON emp.deptno = dept.deptno;

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 29

結合の種類と実行計画

ネステッドループ結合-------------------------------------------------| Id | Operation | Name |-------------------------------------------------| 0 | SELECT STATEMENT | || 1 | NESTED LOOPS | || 2 | TABLE ACCESS BY INDEX ROWID| PA ||* 3 | INDEX UNIQUE SCAN | PK_PA || 4 | TABLE ACCESS BY INDEX ROWID| CH ||* 5 | INDEX RANGE SCAN | IDX_CHPA |-------------------------------------------------

ソートマージ結合------------------------------------| Id | Operation | Name |------------------------------------| 0 | SELECT STATEMENT | || 1 | MERGE JOIN | || 2 | SORT JOIN | ||* 3 | TABLE ACCESS FULL| T1 ||* 4 | SORT JOIN | || 5 | TABLE ACCESS FULL| T2 |------------------------------------

ハッシュ結合------------------------------------------| Id | Operation | Name |------------------------------------------| 0 | SELECT STATEMENT | ||* 1 | HASH JOIN | || 2 | TABLE ACCESS FULL | DEPARTMENTS || 3 | TABLE ACCESS FULL | EMPLOYEES |------------------------------------------

• 結合データ量=小で選択されやすい• 通常インデックスとともに使われる• Oracleのバージョンにより細かい違いが

ある

• 結合データ量=大で選択されやすい• 通常テーブルフルスキャンとともに使われる• 結合条件が等価結合でのみ選択される

• 選択されるケースは少なめ

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 30Copyright © 2017 CO-Sol Inc. All Rights Reserved.

ネステッドループ結合の実行計画を読んでみる

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 31

実行計画を読む手順

1. インデント表形式からツリー構造をイメージ

2. ツリー構造の実行順序を理解

3. オペレーションと実行順序から、各ステップの処理内容をイメージ

※:1. 2. は先行して説明済み

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 32

今回とりあげる実行計画

SQL_ID byzfsqntmu2h5, child number 0-------------------------------------SELECT /*+ USE_NL(CH) LEADING(PA) */ cid, cname, pa.pid, pname FROMch, pa WHERE ch.pid = pa.pid and pa.pid = 1

Plan hash value: 1035406045

------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 10 |00:00:00.09 | 15 | 14 || 1 | NESTED LOOPS | | 1 | 10 | 10 |00:00:00.09 | 15 | 14 || 2 | TABLE ACCESS BY INDEX ROWID| PA | 1 | 1 | 1 |00:00:00.04 | 2 | 2 ||* 3 | INDEX UNIQUE SCAN | PK_PA | 1 | 1 | 1 |00:00:00.02 | 1 | 1 || 4 | TABLE ACCESS BY INDEX ROWID| CH | 1 | 10 | 10 |00:00:00.05 | 13 | 12 ||* 5 | INDEX RANGE SCAN | IDX_CHPA | 1 | 10 | 10 |00:00:00.01 | 3 | 2 |------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

3 - access("PA"."PID"=1)5 - access("CH"."PID"=1)

詳しい人向けの補足12cから導入された最適化機能Batch table access by rowidをOFFにした実行計画

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 33

1. インデント表形式からツリー構造をイメージ

----------------------------------------------------------| Id | Operation | Name | Starts |----------------------------------------------------------| 0 | SELECT STATEMENT | | 1 || 1 | NESTED LOOPS | | 1 || 2 | TABLE ACCESS BY INDEX ROWID| PA | 1 ||* 3 | INDEX UNIQUE SCAN | PK_PA | 1 || 4 | TABLE ACCESS BY INDEX ROWID| CH | 1 ||* 5 | INDEX RANGE SCAN | IDX_CHPA | 1 |----------------------------------------------------------

3 - access("PA"."PID"=1)5 - access("CH"."PID"=1)

0: SEL 1: NL

2: TAIR

4: TAIR 5: IRS

3: IUS

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 34

2. ツリー構造の実行順序を理解

----------------------------------------------------------| Id | Operation | Name | Starts |----------------------------------------------------------| 0 | SELECT STATEMENT | | 1 || 1 | NESTED LOOPS | | 1 || 2 | TABLE ACCESS BY INDEX ROWID| PA | 1 ||* 3 | INDEX UNIQUE SCAN | PK_PA | 1 || 4 | TABLE ACCESS BY INDEX ROWID| CH | 1 ||* 5 | INDEX RANGE SCAN | IDX_CHPA | 1 |----------------------------------------------------------

3 - access("PA"."PID"=1)5 - access("CH"."PID"=1)

0: SEL 1: NL

2: TAIR

4: TAIR 5: IRS

3: IUS

最初に実行

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 35

3. 各ステップの処理内容をイメージ

INDEX RANGE SCAN

TABLE ACCESSBY INDEX ROWID

NL

TABLE ACCESSBY INDEX ROWID

INDEX UNIQUESCAN

-------------------------------------------------| Id | Operation | Name |-------------------------------------------------| 0 | SELECT STATEMENT | || 1 | NESTED LOOPS | || 2 | TABLE ACCESS BY INDEX ROWID| PA ||* 3 | INDEX UNIQUE SCAN | PK_PA || 4 | TABLE ACCESS BY INDEX ROWID| CH ||* 5 | INDEX RANGE SCAN | IDX_CHPA |-------------------------------------------------

3 - access("PA"."PID"=1)5 - access("CH"."PID"=1)

PK_PA

PA

IDX_CHPA

CH

0: SEL 1: NL

2: TAIR

4: TAIR 5: IRS

3: IUS

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 36Copyright © 2017 CO-Sol Inc. All Rights Reserved.

実行計画の統計値を理解する

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 37

実行計画 各ステップの統計値

• 各ステップの統計値が表示される

– 統計値ごとに解釈が異なる : 下位ステップを含めた累積 or そのステップ単体

• 見積統計と実行統計の2種類がある

SELECT * FROM tab0 WHERE col_idx = 'A' AND col_noix='B'--------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 2 (100)| ||* 1 | TABLE ACCESS BY INDEX ROWID| TAB0 | 1 | 2010 | 2 (0)| 00:00:01 ||* 2 | INDEX RANGE SCAN | T0_IDX | 3 | | 1 (0)| 00:00:01 |--------------------------------------------------------------------------------------

1 - filter("COL_NOIX"='B')2 - access("COL_IDX"='A')

各ステップの統計値

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 38

統計値とその解釈

統計値 解釈・意味 累積?

Rows そのステップが上位のステップに返す見積行数 N

Bytes そのステップが上位のステップに返すRowsの見積バイト数 N

Cost そのステップ以下のステップの累積コストコスト=平たく言うと「オラクルが予測した処理時間(単位なし)」

Y

Time そのステップ以下のステップの予想処理時間 Y

SELECT * FROM tab0 WHERE col_idx = 'A' AND col_noix='B'--------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | | 2 (100)| ||* 1 | TABLE ACCESS BY INDEX ROWID| TAB0 | 1 | 2010 | 2 (0)| 00:00:01 ||* 2 | INDEX RANGE SCAN | T0_IDX | 3 | | 1 (0)| 00:00:01 |--------------------------------------------------------------------------------------

1 - filter("COL_NOIX"='B')2 - access("COL_IDX"='A')

0: SEL 1: TIR 2:IRS

Rows=1 Rows=3

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 39

処理フローとRows統計

INDEX RANGE SCAN

TABLE ACCESSBY INDEX ROWID

t0_IDX

TAB0

SELECT * from tab0 WHERE col_idx = 'A' AND col_noix='B'------------------------------------------------------| Id | Operation | Name | Rows |------------------------------------------------------| 0 | SELECT STATEMENT | | ||* 1 | TABLE ACCESS BY INDEX ROWID| TAB0 | 1 ||* 2 | INDEX RANGE SCAN | T0_IDX | 3 |------------------------------------------------------

1 - filter("COL_NOIX"='B')2 - access("COL_IDX"='A')

filter

access

0: SEL 1: TIR 2:IRS

Rows=1 Rows=3

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 40

SQLチューニングとRows統計

• SQLチューニングの1つの指標実行計画の早い段階で、データを絞り込む→ 大量のデータを引き回す必要がなくなるので、処理の高速化に寄与する

• すなわち、Rows統計は小さい値であることが望ましい。できれば、実行計画の早い段階で、小さい値にできることが望ましい

• ただ・・・「Rows統計」は見積統計であることに注意実行統計である「A-Rows」を用いる方がより適切(見積統計と実行統計については後述)

• さらにもう一つ・・・(次ページ)

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 41

Rows統計の注意点

• 明らかにアクセスしたデータ量が異なるのに、両方ともRows=1とは??

• Rowsはそのステップが上位ステップに引き渡す行数を示す

SELECT * from t9 WHERE id = 1

-----------------------------------------------------| Id | Operation | Name | Rows |-----------------------------------------------------| 0 | SELECT STATEMENT | | || 1 | TABLE ACCESS BY INDEX ROWID| T9 | 1 ||* 2 | INDEX UNIQUE SCAN | PK_T9 | 1 |-----------------------------------------------------

SELECT * from t9 WHERE id = 1

------------------------------------------| Id | Operation | Name | Rows |------------------------------------------| 0 | SELECT STATEMENT | | 1 ||* 1 | TABLE ACCESS FULL| T9 | 1 |------------------------------------------

TABLE ACCESS FULL

filterINDEX UNIQUE SCAN

TABLE ACCESS BY INDEX ROWID

access

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 42Copyright © 2017 CO-Sol Inc. All Rights Reserved.

見積統計と実行統計

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 43

実行計画確認方法と見積統計、実行統計

• 確認方法cでのみ、SQL実行における「本当の」統計値を得られる

• 確認方法a、bで得られる統計値は、あくまでも「Oracleが予測した」統計値であることに注意

確認方法 実行計画

統計 備考

a EXPLAIN PLAN +DBMS_XPLAN.DISPLAY

見積 見積 SQLは実行されない

b SQL実行 →DBMS_XPLAN.DISPLAY_CURSOR

実行 見積

c STATISTICS_LEVEL=ALLでSQL実行 → DBMS_XPLAN.DISPLAY_CURSOR(format=>'ALLSTATS LAST')

実行 見積実行

見積統計と実行統計の両方を表示

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 44

c) DBMS_XPLAN.DISPLAY_CURSOR(format=>'ALLSTATS LAST')

SQL> ALTER SESSION SET statistics_level=ALL;SQL> SELECT * from tab0 WHERE col_idx = 'A';(略)SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=>'ALLSTATS LAST'))

PLAN_TABLE_OUTPUT---------------------------------------------------------------------------------------------------SQL_ID 3hrvf65nm048d, child number 0-------------------------------------SELECT * from tab0 WHERE col_idx = 'A'

Plan hash value: 2195618789

------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 16 |00:00:00.01 | 10 || 1 | TABLE ACCESS BY INDEX ROWID| TAB0 | 1 | 16 | 16 |00:00:00.01 | 10 ||* 2 | INDEX RANGE SCAN | T0_IDX | 1 | 16 | 16 |00:00:00.01 | 3 |------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):---------------------------------------------------

2 - access("COL_IDX"='A')

19行が選択されました。

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 45

見積統計と実行統計 (E-xxxとA-xxx)

------------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 16 |00:00:00.01 | 10 || 1 | TABLE ACCESS BY INDEX ROWID| TAB0 | 1 | 16 | 16 |00:00:00.01 | 10 ||* 2 | INDEX RANGE SCAN | T0_IDX | 1 | 16 | 16 |00:00:00.01 | 3 |------------------------------------------------------------------------------------------------

統計の種類

見積統計(E-xxx) Oracleが見積もった(予測した)統計値

実行統計(A-xxx、Starts、Buffersなど)

過去のSQL実行における実際の統計値

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 46

見積統計と実行統計が異なる例

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=>'ALLSTATS LAST'));-----------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |-----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 4 || 1 | TABLE ACCESS BY INDEX ROWID| T0 | 1 | 250 | 1 |00:00:00.01 | 4 ||* 2 | INDEX RANGE SCAN | T0_IX | 1 | 250 | 1 |00:00:00.01 | 3 |-----------------------------------------------------------------------------------------------

SQL> EXPLAIN PLAN FOR SELECT * FROM t0 WHERE col_idx = 'A';SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

: -------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 250 | 489K| 85 (0)| 00:00:01 || 1 | TABLE ACCESS BY INDEX ROWID| T0 | 250 | 489K| 85 (0)| 00:00:01 ||* 2 | INDEX RANGE SCAN | T0_IX | 250 | | 1 (0)| 00:00:01 |-------------------------------------------------------------------------------------

SQL> SELECT col_idx, count(*) FROM t0 GROUP BY col_idx;

C COUNT(*)- ----------A 1B 1C 1X 997

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 47

見積統計と実行統計が異なることの意味

• Oracleが見積に失敗していることを示す

• 対処策:より正確な見積ができるように、それを支援する情報を追加する→ オプティマイザ統計を改善する

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=>'ALLSTATS LAST'));-----------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |-----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 4 || 1 | TABLE ACCESS BY INDEX ROWID| T0 | 1 | 250 | 1 |00:00:00.01 | 4 ||* 2 | INDEX RANGE SCAN | T0_IX | 1 | 250 | 1 |00:00:00.01 | 3 |-----------------------------------------------------------------------------------------------

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 48

オプティマイザ統計の改善による解決

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(null, 't0', method_opt => 'FOR COLUMNS SIZE AUTO col_idx');

PL/SQLプロシージャが正常に完了しました。

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=>'ALLSTATS LAST'));-----------------------------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |-----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 4 || 1 | TABLE ACCESS BY INDEX ROWID| T0 | 1 | 1 | 1 |00:00:00.01 | 4 ||* 2 | INDEX RANGE SCAN | T0_IX | 1 | 1 | 1 |00:00:00.01 | 3 |-----------------------------------------------------------------------------------------------

SQL> EXPLAIN PLAN FOR SELECT * FROM t0 WHERE col_idx = 'A';SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

: -------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | 2007 | 2 (0)| 00:00:01 || 1 | TABLE ACCESS BY INDEX ROWID| T0 | 1 | 2007 | 2 (0)| 00:00:01 ||* 2 | INDEX RANGE SCAN | T0_IX | 1 | | 1 (0)| 00:00:01 |-------------------------------------------------------------------------------------

• ヒストグラムの収集で解決• ヒストグラム=列値の頻度情報

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 49Copyright © 2017 CO-Sol Inc. All Rights Reserved.

Starts実行統計

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 50

Starts実行統計 : オペレーションの実行回数

• 実行計画(見積)では表示されないが、実行計画を理解する助けになるときがある

SELECT cid, cname, pa.pid, pnameFROM ch, paWHERE ch.pid = pa.pid and pa.pid IN (1,2,3)

-------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows |-------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 3 || 1 | NESTED LOOPS | | 1 | 3 | 3 ||* 2 | TABLE ACCESS FULL | CH | 1 | 3 | 3 || 3 | TABLE ACCESS BY INDEX ROWID| PA | 3 | 1 | 3 ||* 4 | INDEX UNIQUE SCAN | PK_PA | 3 | 1 | 3 |-------------------------------------------------------------------------

0: SEL 1: NL

2: TAF

4: TAIR 5: IUS

Starts=3 → 3回実行

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 51

Starts実行統計 : オペレーションの実行回数

SELECT cid, cname, pa.pid, pnameFROM ch, paWHERE ch.pid = pa.pid and pa.pid IN (1,2,3)

-------------------------------------------------------------------------| Id | Operation | Name | Starts | E-Rows | A-Rows |-------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1 | | 3 || 1 | NESTED LOOPS | | 1 | 3 | 3 ||* 2 | TABLE ACCESS FULL | CH | 1 | 3 | 3 || 3 | TABLE ACCESS BY INDEX ROWID| PA | 3 | 1 | 3 ||* 4 | INDEX UNIQUE SCAN | PK_PA | 3 | 1 | 3 |-------------------------------------------------------------------------

INDEX UNIQUE SCAN

TABLE ACCESSBY INDEX ROWID

NL

TABLE ACCESSFULL

CH

PK_PA

PA

access

① ② ③

0: SEL 1: NL

2: TAF

4: TAIR 5: IUS

Starts=3 → 3回実行①

②③

① ② ③

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 52

Questions&

Answers

Copyright © 2017 CO-Sol Inc. All Rights Reserved. 53