Oracle実行計画の説明(二)

12943 ワード

ここでoracle実行計画の各パラメータの意味について説明します
次の例で説明します
ここで補足します:traceのタイプは全部で以下のいくつかあります
シーケンス番号
コマンド#コマンド#
説明する
1
SET AUTOTRACE OFF
これがデフォルトです.Autotraceを閉じます.
2
SET AUTOTRACE ON EXPLAIN
実行計画のみ表示
3
SET AUTOTRACE ON STATISTICS
実行された統計のみ表示
4
SET AUTOTRACE ON
2,3の2つの内容を含む
5
SET AUTOTRACE TRACEONLY
ONと似ていますが、文の実行結果は表示されません
私はSET AUTOTRACE TRACEONLYが好きで、私达の后の例はすべてこのような方式に基づいています
view plaincopy
SQL> select * from departments a where a.department_id in (select b.department_id from employees b where b.employee_id=205);  
  
  
Execution Plan  
----------------------------------------------------------  
Plan hash value: 2782876085  
  
----------------------------------------------------------------------------------------------  
| Id  | Operation                    | Name          | Rows  | Bytes | Cost (%CPU)| Time     |  
----------------------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT             |               |     1 |    27 |     2   (0)| 00:00:01 |  
|   1 |  NESTED LOOPS                |               |     1 |    27 |     2   (0)| 00:00:01 |  
|   2 |   TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     1 |     7 |     1   (0)| 00:00:01 |  
|*  3 |    INDEX UNIQUE SCAN         | EMP_EMP_ID_PK |     1 |       |     0   (0)| 00:00:01 |  
|   4 |   TABLE ACCESS BY INDEX ROWID| DEPARTMENTS   |    27 |   540 |     1   (0)| 00:00:01 |  
|*  5 |    INDEX UNIQUE SCAN         | DEPT_ID_PK    |     1 |       |     0   (0)| 00:00:01 |  
----------------------------------------------------------------------------------------------  
  
Predicate Information (identified by operation id):  
---------------------------------------------------  
  
   3 - access("B"."EMPLOYEE_ID"=205)  
   5 - access("A"."DEPARTMENT_ID"="B"."DEPARTMENT_ID")  
  
  
Statistics  
----------------------------------------------------------  
          1  recursive calls  
          0  db block gets  
          4  consistent gets  
          0  physical reads  
          0  redo size  
        749  bytes sent via SQL*Net to client  
        492  bytes received via SQL*Net from client  
          2  SQL*Net roundtrips to/from client  
          0  sorts (memory)  
          0  sorts (disk)  
          1  rows processed 

  
1行1行見てみましょう.
一、表部分
1、Plan hash value:
[sql] view plaincopy
Plan hash value: 2782876085 
この行はこの文のhash値であり、oracleが各文に対して生成した実行計画をshare poolに配置し、初めてハード解析を経てhash値を生成することを知っています.次回この文を実行するときはhash値を比較し、同じであればハード解析を実行しないでください.
2、操作(操作)
ここのものは多くなって、sqlを分解して、私にいっしょに上のsqlを見せて、このsqlの第1歩はemployeeですid=25ここではemployeeidにはプライマリ・キーが作成され、プライマリ・キーにはデフォルトで一意のインデックスが作成されます.ここは「=」で制限されているので、unique scan方式を歩きます.その他の方法については、Oracle実行計画の説明(一)を参照してください.
もう一つの知識点は、テーブルのリンク操作を知ることです.私の別の文章を参照してください.
3、Name(操作対象オブジェクト)
例えば前例の2行目のoperation(TABLE ACCESS BY INDEX ROWID)ここでのTABLEオブジェクトはEMPLOYES
4、Row、Cardinalityというところもあります(plsqldevで計画ウィンドウを説明します)
ここでは、データ・クエリーの行数です.たとえば、前の例の4行目、departmentsという表は27行をスキャンし、サブクエリー(select b.department_id from employees b where b.employee_id=205)の値と比較します.=(注:ほとんどの場合=で置き換えることができませんが、ここでは特例です)を使うと違います.
[sql] view plaincopy
SQL> select * from departments a where a.department_id = (select b.department_id from employees b where b.employee_id=205);  
  
  
Execution Plan  
----------------------------------------------------------  
Plan hash value: 3449260133  
  
-----------------------------------------------------------------------------------------------  
| Id  | Operation                     | Name          | Rows  | Bytes | Cost (%CPU)| Time     |  
-----------------------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT              |               |     1 |    20 |     2   (0)| 00:00:01 |  
|   1 |  TABLE ACCESS BY INDEX ROWID  | DEPARTMENTS   |     1 |    20 |     1   (0)| 00:00:01 |  
|*  2 |   INDEX UNIQUE SCAN           | DEPT_ID_PK    |     1 |       |     0   (0)| 00:00:01 |  
|   3 |    TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |     1 |     7 |     1   (0)| 00:00:01 |  
|*  4 |     INDEX UNIQUE SCAN         | EMP_EMP_ID_PK |     1 |       |     0   (0)| 00:00:01 |  
-----------------------------------------------------------------------------------------------  
  
Predicate Information (identified by operation id):  
---------------------------------------------------  
  
   2 - access("A"."DEPARTMENT_ID"= (SELECT /*+ */ "B"."DEPARTMENT_ID" FROM "EMPLOYEES"  
              "B" WHERE "B"."EMPLOYEE_ID"=205))  
   4 - access("B"."EMPLOYEE_ID"=205)  
  
  
Statistics  
----------------------------------------------------------  
          0  recursive calls  
          0  db block gets  
          4  consistent gets  
          0  physical reads  
          0  redo size  
        749  bytes sent via SQL*Net to client  
        492  bytes received via SQL*Net from client  
          2  SQL*Net roundtrips to/from client  
          0  sorts (memory)  
          0  sorts (disk)  
          1  rows processed  
   

5、Byte
スキャンされたデータのバイト数
6、Cost
ここは前回お話ししましたが、ここで簡単にお話ししましょう.
costには単位がなく、相対値であり、sql文がcboで解析して実行する場合、oracleがcboコストを評価し、実行計画を選択するために使用します.
数式:Cost=(Single block I/O cost+Multiblock I/O cost+CPU cost)/sreadtim
明確な意味はありませんが、比較するととても役に立ちます.
7、Time
各セグメントの実行時間
二、Predicate Information
ここにはフィルタ条件が2つあります.
1、索引(access)
上記の例のaccess(「B」.「EMPLOYE_ID」=205)のように、ここではフィルタ条件としてインデックスを用いる
2、非索引(filter)、以下の例を見る
[sql] view plaincopy
SQL> select employee_id  
                  from employees c  
                 where c.first_name = 'Steven'   2    3  ;  
  
  
Execution Plan  
----------------------------------------------------------  
Plan hash value: 1445457117  
  
-------------------------------------------------------------------------------  
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |  
-------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT  |           |     1 |    11 |     3   (0)| 00:00:01 |  
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |     1 |    11 |     3   (0)| 00:00:01 |  
-------------------------------------------------------------------------------  
  
Predicate Information (identified by operation id):  
---------------------------------------------------  
  
   1 - filter("C"."FIRST_NAME"='Steven')  
  
  
Statistics  
----------------------------------------------------------  
          1  recursive calls  
          0  db block gets  
          8  consistent gets  
          0  physical reads  
          0  redo size  
        574  bytes sent via SQL*Net to client  
        492  bytes received via SQL*Net from client  
          2  SQL*Net roundtrips to/from client  
          0  sorts (memory)  
          0  sorts (disk)  
          2  rows processed 

ここでのフィルタ条件はFIRST_NAME、でもFIRST_NAMEはインデックスを作成していません.このときfilterを使用してタグを付けます.
三、Statistics(統計)
ここはポイントですが、疲れたら、よだれを飲みに行ってもいいです.O(∩_∩)O~
AUTOTRACE Statics列解釈
シーケンス番号
列名
説明する
1
recursive calls
再帰調査
2
db block gets
buffer cacheから読み込まれたblockの数
3
consistent gets
buffer cacheから読み込まれたundoデータのblockの数
4
physical reads
ディスクから読み込まれたblockの数
5
redo size
DMLによって生成されるredoのサイズ
6
sorts (memory)
メモリで実行されるソート数
7
sorts (disk)
ディスクで実行されるソート数
1、recursive calls(重点説明)
公式サイトのrecursive callsに対する解釈は以下の通りです.
       Recursive Calls:  Number of recursive calls generated at both the user and system level.   
       Oracle Database maintains tables used for internal processing. When it needs to change these tables, Oracle Database generates an internal SQL statement, which in turn generates a recursive call.In short, recursive calls are basically SQL performed on behalf of your SQL. So, if you had to parse the query, for example, you might have had to run some other queries to get data dictionary information. These would be recursive calls. Space management, security checks, calling PL/SQL from SQL—all incur recursive SQL calls.
IBMにも解説がありますので、興味があればご覧ください
       http://publib.boulder.ibm.com/tividd/td/ITMD/SC23-4724-00/en_US/HTML/oraclepac510rg59.htm
まとめてみます.
SQL文を実行すると、他のSQL文の呼び出しが発生します.これらの追加の文は'rcursive calls'または'rcursive SQL statements'と呼ばれます.
IBMのドキュメントでは、Recursive Callをトリガーする6つの状況について説明しています.
次のようになります.
(1)insertを作成する場合、rowレコードを保存するのに十分なスペースがありません.OracleはRecursive Callによって動的にスペースを割り当てます.
(2)DDL文を実行するとき、ORACLEは常に暗黙的にいくつかのrecursive SQL文を発行して、データ辞書情報を修正して、このDDL文を正常に実行します.
(3)Shared Poolが小さすぎるとdata dictionary cacheも小さくなり、ORACLEのシステムデータ辞書情報を格納するのに十分なスペースがない場合、Recursive callsが発生し、これらのRecursive callsはデータ辞書情報をハードディスクからメモリに読み込む.
(4)ストアド・プロシージャ,トリガ内にSQL呼び出しがあればrecursive SQLも発生する.
これらの場合、主にデータ辞書に対するクエリーであり、通常、1回目の実行時に発生し、2回目の実行は一般的に著しく低減される.再帰は大量の資源を消費する必要があり、操作が複雑であれば、問題が発生しやすい!
例を挙げてみましょう.
[sql] view plaincopy
SQL> select * from employees;  
  
107 rows selected.  
  
  
Execution Plan  
----------------------------------------------------------  
Plan hash value: 1445457117  
  
-------------------------------------------------------------------------------  
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |  
-------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT  |           |   107 |  7276 |     3   (0)| 00:00:01 |  
|   1 |  TABLE ACCESS FULL| EMPLOYEES |   107 |  7276 |     3   (0)| 00:00:01 |  
-------------------------------------------------------------------------------  
  
  
Statistics  
----------------------------------------------------------  
          1  recursive calls  
          0  db block gets  
         15  consistent gets  
          0  physical reads  
          0  redo size  
       9997  bytes sent via SQL*Net to client  
        569  bytes received via SQL*Net from client  
          9  SQL*Net roundtrips to/from client  
          0  sorts (memory)  
          0  sorts (disk)  
        107  rows processed  

  
もう一度実行しましょう
[sql] view plaincopy
SQL> select * from employees;  
  
107 rows selected.  
  
  
Execution Plan  
----------------------------------------------------------  
Plan hash value: 1445457117  
  
-------------------------------------------------------------------------------  
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |  
-------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT  |           |   107 |  7276 |     3   (0)| 00:00:01 |  
|   1 |  TABLE ACCESS FULL| EMPLOYEES |   107 |  7276 |     3   (0)| 00:00:01 |  
-------------------------------------------------------------------------------  
  
  
Statistics  
----------------------------------------------------------  
          0  recursive calls  
          0  db block gets  
         15  consistent gets  
          0  physical reads  
          0  redo size  
       9997  bytes sent via SQL*Net to client  
        569  bytes received via SQL*Net from client  
          9  SQL*Net roundtrips to/from client  
          0  sorts (memory)  
          0  sorts (disk)  
        107  rows processed 

  
1回目のemployeesクエリでは1回のrecursive Callが生成され,2回目のクエリではデータ辞書の情報がcacheに入っているため,2回目のrecursive callは0である.2回目も完全cacheがなければrecursive callも発生するが、回数は1回目より少ない.
他は文字通りに見えるので、あまり説明する必要はないでしょう.
原文URL:
http://blog.csdn.net/rulev5/article/details/6988180