Oracle EXPLAIN PLAN用法

1.SQL語句的執行計劃

使用EXPLAIN PLAN語句來確定Oracle數據庫下指定SQL語句的執行計劃,這個語句插入每一步執行計劃的行描述到指定表中。你也可使用EXPLAIN PLAN語句作爲SQL跟蹤工具的一部分。

EXPLAIN PLAN命令的語法如下:

EXPLAIN PLAN
   [ SET STATEMENT_ID = string ]
   [ INTO [ schema. ] table_name [ @ dblink ] ]
FOR sql_statement ;

EXPLAIN PLAN的相關選下如下:

  • STATEMENT_ID

SQL語句的唯一標識符。通過使用SQL語句的標識符,可以向一個計劃表中存入多條SQL語句。

  • TABLE_NAME

存儲執行計劃的計劃表的名稱。此表必須已經存在並且與標準表結構一致。如果沒有指定計劃表名稱,EXPLAIN PLAN會嘗試使用表名PLAN_TABLE.

  • SQL_STATEMENT

你想要知道其執行計劃的那條SQL語句。這條SQL語句必須是有效的。並且你也必須有足夠的權限來執行它。這條SQL語句可以含有綁定變量。

2.計劃表

默認情況下,Oracle會將執行計劃插入如到一張名爲PLAN_TABLE的表中。可以使用腳本utlexplain.sql來創建自己的計劃表。這個腳本位於Oracle軟件安裝目錄的子目錄$ORACLE_HMOE/rmdbs/admin/中。然而,從Oracle 10g開始,Oracle會創建一個全局臨時表PLAN_TABLE供所有用戶使用,所以通常情況下不需要創建自己的計劃表。由於此默認的計劃表是一個全局臨時表,所以你無法看到其他會話插入的執行計劃,你的執行計劃也會隨着自己會話的結束而自動消失。

(計劃表)

列名

類型

描述

STATEMENT_ID

VARCHAR2(30)

在EXPLAIN PLAN的SET STATEMENT_ID子句提供的SQL語句的唯一標誌符。

PLAN_ID

NUMBER

執行計劃的在全局表plan_table中的唯一標識符

TIMESTAMP

DATE

EXPLAN PLAN語句執行的日期和時間

REMARKS

VARCHAR2(80)

註釋

OPERATION

VARCHAR2(30)

執行的操作類型。如TABLE ACCESS,SORT或HASH JOIN

OPTIONS

VARCHAR2(225)

操作的附加信息,例如,以TABLE SCAN爲例,選項可能是FULL或BY ROWID

OBJECT_NODE

VARCHAR2(128)

如果是分佈式查詢,這一列表示用於引用對象的數據庫鏈接名稱。如果並行查詢,它的值可能對應一個臨時的結果集。

OBJECT_OWNER

VARCHAR2(30)

對象的名字

OBJECT_NAME

VARCHAR2(30)

對象名稱

OBJECT_ALIAS

VARCHAR2(65)

對象的別名

OBJECT_INSTANCE

NUMERIC

對象在SQL語句中的位置

OBJECT_TYPE

VARCHAR2(30)

對象的類型(表,索引等)

OPTIMIZER

VARCHAR2(255)

解釋SQL語句時生效的優化器

SEARCH_COLUMNS

NUMBERIC

未使用

ID

NUMERIC

執行計劃的ID號

PARENT_ID

NUMERIC

上一個步驟的ID號

DEPTH

NUMERIC

操作的深度

POSITION

NUMERIC

如果兩個步驟有相同的父步驟,有更低POSITION值的步驟將被先執行

COST

NUMERIC

優化器估算出來的此操作的相對成本

CARDINALITY

NUMERIC

優化器預期這一步將飯後的記錄數

BYTES

NUMERIC

預計這一步將返回的字節數

OTHER_TAG

VARCHAR2(255)

標識OTHER列中的值的類型。

PARTITION_START

VARCHAR2(255)

訪問的分區範圍的起始分區

PARTITION_STOP

VARCHAR2(255)

訪問的分區範圍的結束分區

PARTITION_ID

NUMERIC

計算PARTITION_STARTPARTITION_STOP列的值對的ID

OTHER

LONG

對於分佈式查詢,這列可能是包含發往遠程數據庫的SQL語句的文本。對於並行查詢,它比啊是並行從屬進程執行的SQL語句。

DISTRIBUTION

VARCHAR2(30)

描述記錄是如何從一組並行查詢從屬進程分配到後續的“消費者”從屬進程的。

CPU_COST

NUMERIC

估算出來的操作的CPU成本

IO_COST

NUMERIC

估算出來的的操作的IO成本

TEMP_SPACE

NUMERIC

估算出來的這一步操作所使用的臨時存儲的空間大小

ACCESS_PREDICATES

VARCHAR2(4000)

SQL語句中,確定如何在當前步驟中提取記錄的子句。

FILTER_PREDICATES

VARCHAR2(4000)

SQL語句中確定對見記錄進行過濾的子句路,如WHERE子句在非索引列上的條件。

PROJECTION

VARCHAR2(4000)

決定將返回的記錄的子句,通常是SELECT後面的字段列表

TIME

NUMBER(20,2)

優化器爲這一步執行估算的時間消耗

QBLOCK_NAME

VARCHAR2(30)

查詢塊的唯一標識符。

 

(常見的執行計劃操作)

操   作

選  項

描  述

表的訪問路徑

TABLE ACCESS

FULL

全表掃描,他會讀取表中的每一條記錄(嚴格地說,它讀取表的高水位以內的每個數據塊)

CLUSTER

通過索引簇的鍵來訪問數據

HASH

通過散鍵列來訪問表中匹配特定的散列值的一條或多條記錄

BY INDEX ROWID

通過指定ROWID來訪問表中的單條記錄。ROWID是訪問單條記錄的最快捷的方式。通常,ROWID的信息都是有一個相關的索引檢索而來

BY USER ROWID

通過提供一個綁定變量、字面變量或WHERE CURRENT OF CURSOR子句來通過ROWID進行訪問

BY GLOBAL INDEX ROWID

通過由全局分區索引獲得的ROWID進行訪問

BY LOCAL INDEX ROWID

通過本地分區索獲得的ROWID進行訪問

SAMPLE

使用SAMPLE子句得到結果集的一個經過採樣的子集

EXTERNAL TABLE ACCESS

 

訪問一張外部表

RESULT CACHE

 

這個SQL結果集可能來自結果集緩存

MAT_VIEW REWIRTE ACCESS

 

SQL語句被重寫以利用物化視圖

索引操作

ADN_EQUAL

 

 合併來自一個或多個索引掃描的結果集

INDEX

 UNIQUE SCAN

只返回一條記錄的地址(ROWID)的索引檢索

RANGE SCAN

 返回多條記錄的ROWID的索引檢索。之所以可以這樣返回,是因爲是非唯一索引或是使用了區間操作符(例如,>)

FULL SCAN

 按照索引的順序掃描整個索引

KIP SCAN

 搜索碎索引鍵中哦非前導列的索引掃描

FULL SCAN(MAX/MIN)

 檢索最高或最低的索引條目

FAST FULL SCAN

 按照塊順序掃描索引的每個條目,可能會使用多塊讀取

DOMAIN INDEX

 

 域索引(用戶定義的索引類型)檢索

位圖操作

BITMAP

CONVERSION

將ROWID轉換成位圖或將位圖轉換成ROWID

INDEX

從位圖中提取一個值或一個範圍的值

MERGE

合併多個位圖

MINUS

從一個位圖中減去另一個位圖

OR

按位(bit-wise)對兩個位圖做OR操作

表連接

CONNECT BY

 

對前一個步驟的輸出結果執行一個層次化的自聯接操作

MERGE JOIN

 

對前一個步驟的輸出結果執行一次合併聯接

NESTED LOOPS

 

對前一個步驟執行嵌套循環聯接。對於上層的結果集中的每一行,都會掃描下層的結果集以找到匹配的記錄

HASH JOIN

 

對兩個記錄源(row source)進行散列聯接

任何連接操作

OUTER

此連接爲外聯接

任何連接操作

ANTI

此連接爲反聯接

任何連接操作

SEMI

此連接爲半聯接

任何連接操作

CARTESIAN

一個結果集中的每一條記錄與另一個結果中的每一條記錄進行聯接

集合操作

CONCATENATION

 

與顯示指定一個UNION語句一樣,多個結果集被按照同樣的方式做合併。它通常會發生在對索引列使用OR語句時

INTERSECTION

 

對兩個結果集進行比較,只返回在兩個結果集中都存在的記錄。通常只有顯式地使用INTERSECT子句,這個操作纔會發生

MINUS

 

除在第二個結果中出現過的記錄外,返回一個結果中的所有記錄。它是使用MINUS集合操作符的結果

UNION-ALL

 

對兩個結果集進行合併,並返回兩個結果集中的所有記錄

UNION

 

對兩個結果集進行合併,並返回兩個結果集中的所有記錄,但是不返回重複記錄

VIEW

 

要麼訪問一個視圖定義,要麼創建一個臨時表來存儲結果集

其他雜項

FOR UPDATE

 

由於FOR UPDATE子句的原因,返回的記錄都會被鎖住

COLLECTION ITERATOR

各種

從一個表函數提取記錄的操作(也就是 FROM TABLE())

FAST DUAL

 

訪問DUAL表,以避免從緩衝區高數緩存中讀取

FILTER

 

從結果集中排除掉不匹配給定選取條件的記錄

REMOTE

 

通過數據庫鏈接訪問一個外部的數據庫

FIRST ROW

 

獲取查詢的第一條記錄

SEQUENCE

 

使用Oracle序列號生成器來獲得一個唯一的序列號

INLIST ITERATOR

 

對於IN列表中的每個值都執行一次下一個操作

LOAD AS SELECT

 

表示這是一個基於SELECT語句的直接路徑INSERT操作

FIXED TABLE

 

訪問固定的(X$或V$)表

FIXED INDEX

 

訪問固定表X$上的索引

WINDOW

BUFFER

支持分析函數(如OVER())的內部操作

WINDOW

SORT [PUSHED]RANK

分析函數需要爲實現RANK()函數執行一次排序操作

 分區操作

PARTITION

SINGLE

訪問單個分區

ITERATOR

訪問多個分區

ALL

訪問所有分區

INLIST

基於IN列表中的值來訪問多個分區

 彙總操作

COUNT

 

爲了滿足COUNT()函數而計算結果集中的記錄數

COUNT

STOPKEY

計算結果集中的記錄數,當達到一定數量後就停止處理。這通常發生在使用了WHERE子句,並指定了一個最大值ROWNUM(例如,WHERE ROWNUM<=10)的情況下

BUFFER

SORT

對臨時結果集做的一次內存排序

HASH

GROUP BY

使用散列操作而不是排序操作實現GROUP BY

INLIST

ITERATOR

對於IN列表中的每個值都實現一次子操作

SORT

ORDER BY

爲了滿足ORDER BY子句而對結果集進行排序

AGGREGATE

當在已經分好組的數據上使用分組函數是會出現此操作

JOIN

爲了準備合併連接而對記錄進行排序

UNIQUE

排除重複記錄的排序操作,通常是使用DISTINCT子句的結果

GROUP BY

爲GROUP BY子句對結果集進行排序分組

GROUP BY NOSORT

不需要進行排序操作的GROUP BY操作

GROUP BY ROLLUP

含有ROLLUP選項的GROUP BY操作

GROUP BY CUBE

含有CUBE選項的GROUP BY操作

 

3.查看執行計劃


當SQL語句的執行計劃生成以後,我們就可以去查看SQL語句的執行計劃了。有兩種方法可以查看執行計劃:直接查看計劃表和DBMS_XPLAN.DISPALY表函數。

第一種方法:

爲了更好地理解計劃表中的數據,需要針對計劃表做層次查詢。通過SELECT語句的 CONNECT BY子句對PARENT_ID和ID兩列進行自連接。這種查詢語句通常的寫法如下:

select rtrim(lpad(' ', 2 * level) || rtrim(operation) || ' ' || rtrim(options)) description,
       object_owner,
       object_name,
       cost,
       cardinality,
       bytes,
       io_cost,
       cpu_cost
  from plan_table
connect by prior id = parent_id
 start with id = 0

 

第二種方法:

與手工查詢計劃表相比,使用DBMS_XPLAN通常可以更好的結果,它的語法更加簡單,還提供了多種有用的輸出格式,並且可以利用緩存的執行計劃統計信息。

調用DBMS_XPLAN函數最簡單的方法就是使用 select * from table()語句,如下面的語句:

select * from table(dbms_xplan.function(options));

最常用的兩個DBMS_XPLAN函數:

DBMS_XPLAN.DISPLAY(
   table_name    IN  VARCHAR2  DEFAULT 'PLAN_TABLE',
   statement_id  IN  VARCHAR2  DEFAULT  NULL,
   format        IN  VARCHAR2  DEFAULT  'TYPICAL',
   filter_preds  IN  VARCHAR2 DEFAULT NULL);
  
DBMS_XPLAN.DISPLAY_CURSOR(
   sql_id        IN  VARCHAR2  DEFAULT  NULL,
   child_number  IN  NUMBER    DEFAULT  NULL,
   format        IN  VARCHAR2  DEFAULT  'TYPICAL');

 

4.Examples

創建emp_test表

 create table emp_test as select *from emp; 

create unique index EMP_TEST_U1 on EMP_TEST (empno);
create index emp_test_n1 on EMP_TEST (ename);

通過EXPLAIN PLAN語句,插入指定SQL語句的執行計劃。

SQL> explain plan set statement_id ='plan_sql_id' for select * from emp_test t where t.ename='SCOTT';
 
Explained

 

手動查詢計劃表查看計劃:

SQL> select rtrim(lpad(' ', 2 * level) || rtrim(operation) || ' ' || rtrim(options)) description,
  2         object_owner,
  3         object_name,
  4         cost,
  5         cardinality,
  6         bytes,
  7         io_cost,
  8         cpu_cost
  9    from plan_table
 10  connect by prior id = parent_id
 11   start with id = 0;
 
DESCRIPTION                       OBJECT_OWNER  OBJECT_NAME   COST  CARDINALITY  BYTES  IO_COST  CPU_COST
-------------------------------- ------------- ------------- ------ -----------  -----  -------  ---------
  SELECT STATEMENT                                             2        1          38       2     14733
    TABLE ACCESS BY INDEX ROWID   SCOTT         EMP_TEST       2        1          38       2     14733
      INDEX RANGE SCAN            SCOTT         EMP_TEST_N1    1        1                   1     7321

 

 

調用DBMS_XPLAN函數查看:

SQL> select * from table(dbms_xplan.display());
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1758671844
--------------------------------------------------------------------------------
| Id  | Operation                   | Name        | Rows  | Bytes | Cost (%CPU)|
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |             |     1 |    38 |     2   (0)|
|   1 |  TABLE ACCESS BY INDEX ROWID| EMP_TEST    |     1 |    38 |     2   (0)|
|*  2 |   INDEX RANGE SCAN          | EMP_TEST_N1 |     1 |       |     1   (0)|
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("T"."ENAME"='SCOTT')

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章