orale性能調優工具--EXPLAIN PLAN和DBMS_XPLAN

概述:有多種方法可用來找出哪些sql語句需要優化,最簡單的方法都是分析保存在v$sql視圖中的緩存的SQL信息。這個視圖包含存儲在共享池中的SQL語句相關的信息,雖然邏輯讀(logical read)最多或者時間消耗(elapsed time)最大的SQL語句通常都是優化的好目標,然而只有仔細觀察每一個步驟才能找準最佳優化時機。在10g中,我們可以使用緩存的查詢計劃的統計信息來定位sql執行中可能需要特別注意的步驟,如視圖v$sql_plan展示所有緩存的sql語句的執行計劃,而v$sql_plan_statistics則展示計劃中每個步驟的執行次數,IO次數以及處理得記錄數。

1.通過挖掘v$sql,確定具有較高消耗時間,CPU或IO需求的SQL語句。通過使用v$sql_plan和v$sql_plan_statistics,我們可以找到執行操作不盡人意的的SQL語句。

a.select sql_id, child_number, sql_text, elapsed_time
  from (select sql_id,
               child_number,
               sql_text,
               elapsed_time,
               cpu_time,
               disk_reads,
               rank() over(order by elapsed_time desc) as elapsed_rank
          from v$sql)
 where elapsed_rank <= 10;

b.DBMS_XPLAN.DISPLAY_CURSOR()看執行計劃

SQL> SELECT * FROM TABLE(DBMS_XPLAN.display_cursor('6axh886a13hhn','0'));

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  6axh886a13hhn, child number 0
-------------------------------------
select NVL(LINE,'NONE') LINE into :b0  from (select A.DESCRIPTION LINE
,count(LH.LOTID)  from LOTHISTORY LH ,AREA A where
((((((((LH.WORKAREA=A.WORKAREA and A.WORKAREA='EOL') and
LH.WORKAREA='EOL') and A.LEVELNO=2) and A.DETAILAREATYPE='Normal') and
LH.OLDLINEID=A.AREAID) and LH.LOTID=trim(:b1)) and
LH.EVENTID='TrackOut') and LH.OLDOPERATIONID in ('BFOP001')) group by
A.DESCRIPTION order by count(LOTID) desc  ) where ROWNUM=1

Plan hash value: 4058338800


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------
| Id  | Operation                         | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |                      |       |       |   343 (100)|          |
|*  1 |  COUNT STOPKEY                    |                      |       |       |            |          |
|   2 |   VIEW                            |                      |     1 |   129 |   343   (1)| 00:00:01 |
|*  3 |    SORT ORDER BY STOPKEY          |                      |     1 |    73 |   343   (1)| 00:00:01 |
|   4 |     HASH GROUP BY                 |                      |     1 |    73 |   343   (1)| 00:00:01 |
|   5 |      NESTED LOOPS                 |                      |       |       |            |          |
|   6 |       NESTED LOOPS                |                      |     1 |    73 |   341   (0)| 00:00:01 |


PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|*  7 |        TABLE ACCESS BY INDEX ROWID| LOTHISTORY           |     1 |    41 |   339   (0)| 00:00:01 |
|*  8 |         INDEX RANGE SCAN          | IDX_LOTHISTORY_LOTID |   466 |       |     6   (0)| 00:00:01 |
|*  9 |        INDEX RANGE SCAN           | AREA_PK              |     1 |       |     1   (0)| 00:00:01 |
|* 10 |       TABLE ACCESS BY INDEX ROWID | AREA                 |     1 |    32 |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------


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


   1 - filter(ROWNUM=1)
   3 - filter(ROWNUM=1)


PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   7 - filter(("LH"."OLDOPERATIONID"='BFOP001' AND "LH"."EVENTID"='TrackOut' AND "LH"."OLDLINEID"
              IS NOT NULL AND "LH"."WORKAREA"='EOL'))
   8 - access("LH"."LOTID"=TRIM(:B1))
   9 - access("A"."WORKAREA"='EOL' AND "LH"."OLDLINEID"="A"."AREAID")
       filter("LH"."WORKAREA"="A"."WORKAREA")
  10 - filter(("A"."LEVELNO"=2 AND "A"."DETAILAREATYPE"='Normal'))

40 rows selected.

2.dbms_xplan工具介紹:

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

調用dbms_xplan函數最簡單的方法是使用select * from table()語法:

最常用的兩個函數:

function display(table_name   varchar2      default 'PLAN_TABLE',
                   statement_id varchar2      default null,
                   format       varchar2      default 'TYPICAL',
                   filter_preds varchar2      default null)
  return dbms_xplan_type_table

 function display_cursor(sql_id           varchar2 default  null,
                          cursor_child_no  integer  default  0,
                          format           varchar2 default  'TYPICAL')
  return dbms_xplan_type_table

DISPLAY函數展示了PLAN_TABLE中的執行計劃,而DISPLAY_CURSOR則展示了再v$sql_plan中緩存的執行計劃的信息。

(1).BASIC只展示執行計劃:

SQL> SELECT * FROM TABLE(DBMS_XPLAN.display_cursor('9q26krp7wx6y8','0','BASIC'));


PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
EXPLAINED SQL STATEMENT:
------------------------
insert into LOTCARDDEFECT  (select D.* ,trim(:b0) SHIFTDAY
,TO_CHAR(SYSTIMESTAMP,'YYYYMMDDHH24MISSFF6')  from (select LC.LOTID
,D.REASONCODE ,D.WORKAREA ,D.OPERATIONID ,sum(D.DEFECTQUANTITY) QTY
from PRODUCTSPEC PS ,LOTDEFECTDETAIL D ,LOTCARD LC ,DEFECTCODE DC where
((((((((((((1=1 and PS.WORKAREA=D.WORKAREA) and
PS.PRODUCTSPECID=D.PRODUCTSPECID) and D.LOTID like (LC.LOTID||'%')) and
D.REASONCODE=DC.DEFECTCODE) and D.WORKAREA=DC.WORKAREA) and
PS.WORKAREA<>'EOL') and D.WORKAREA<>'EOL') and PS.PRODUCTFAMILY in
('VERMONT','VERMONT+')) and LC.SHIFTDAY=trim(:b0)) and D.REASONCODE in


PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
(select DEFECTCODE  from LOTCARDDEFECTHEADER DH where
((DH.HEADERTYPE='ITEM' and DH.WORKAREA<>'EOL') and
DH.REVISION='2014-07-07'))) and D.TESTLEVEL=0) and DC.TESTFLAG<>'Y')
group by LC.LOTID,D.WORKAREA,D.OPERATIONID,D.REASONCODE union select
LC.LOTID ,'ETC' REASONCODE ,D.WORKAREA ,D.OPERATIONID
,sum(D.DEFECTQUANTITY) QTY  from PRODUCTSPEC PS ,LOTDEFECTDETAIL D
,LOTCARD LC ,DEFECTCODE DC where ((((((((((((1=1 a

Plan hash value: 964220270

--------------------------------------------------------------------

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name                |
--------------------------------------------------------------------
|   0 | INSERT STATEMENT                     |                     |
|   1 |  LOAD TABLE CONVENTIONAL             |                     |
|   2 |   VIEW                               |                     |
|   3 |    SORT UNIQUE                       |                     |
|   4 |     UNION-ALL                        |                     |
|   5 |      HASH GROUP BY                   |                     |
|   6 |       HASH JOIN                      |                     |
|   7 |        HASH JOIN                     |                     |
|   8 |         TABLE ACCESS FULL            | PRODUCTSPEC         |


PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   9 |         HASH JOIN                    |                     |
|  10 |          TABLE ACCESS FULL           | LOTDEFECTDETAIL     |
|  11 |          MERGE JOIN CARTESIAN        |                     |
|  12 |           TABLE ACCESS BY INDEX ROWID| LOTCARD             |
|  13 |            INDEX RANGE SCAN          | LOTCARD_IDX01       |
|  14 |           BUFFER SORT                |                     |
|  15 |            SORT UNIQUE               |                     |
|  16 |             TABLE ACCESS FULL        | LOTCARDDEFECTHEADER |
|  17 |        TABLE ACCESS FULL             | DEFECTCODE          |
|  18 |      HASH GROUP BY                   |                     |
|  19 |       HASH JOIN RIGHT ANTI           |                     |

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|  20 |        TABLE ACCESS FULL             | LOTCARDDEFECTHEADER |
|  21 |        HASH JOIN                     |                     |
|  22 |         TABLE ACCESS FULL            | DEFECTCODE          |
|  23 |         HASH JOIN                    |                     |
|  24 |          TABLE ACCESS FULL           | LOTDEFECTDETAIL     |
|  25 |          MERGE JOIN CARTESIAN        |                     |
|  26 |           TABLE ACCESS BY INDEX ROWID| LOTCARD             |
|  27 |            INDEX RANGE SCAN          | LOTCARD_IDX01       |
|  28 |           BUFFER SORT                |                     |
|  29 |            TABLE ACCESS FULL         | PRODUCTSPEC         |
|  30 |      HASH GROUP BY                   |                     |


PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|  31 |       HASH JOIN                      |                     |
|  32 |        TABLE ACCESS FULL             | DEFECTCODE          |
|  33 |        HASH JOIN                     |                     |
|  34 |         TABLE ACCESS FULL            | LOTDEFECTDETAIL     |
|  35 |         MERGE JOIN CARTESIAN         |                     |
|  36 |          TABLE ACCESS BY INDEX ROWID | LOTCARD             |
|  37 |           INDEX RANGE SCAN           | LOTCARD_IDX01       |
|  38 |          BUFFER SORT                 |                     |
|  39 |           TABLE ACCESS FULL          | PRODUCTSPEC         |
--------------------------------------------------------------------

66 rows selected.

(2).TYPICAL:默認輸出設置

(3).ALL:輸出所有信息

DBMS_XPLAN 輸出例子:

explain plan for select department_name, last_name, job_title
  from hr.employees
  join hr.departments
 using (department_id)
  join hr.jobs
 using (job_id)
 order by department_name, job_title;


SQL> select * from table(dbms_xplan.display(null,null,'TYPICAL'));

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1492005721
----------------------------------------------------------------------------------------------
| Id  | Operation       | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |     | 106 | 6678 |  10  (20)| 00:00:01 |
|   1 |  SORT ORDER BY       |     | 106 | 6678 |  10  (20)| 00:00:01 |
|*  2 |   HASH JOIN       |     | 106 | 6678 |   9  (12)| 00:00:01 |
|   3 |    MERGE JOIN       |     | 107 | 5029 |   6  (17)| 00:00:01 |
|   4 |     TABLE ACCESS BY INDEX ROWID| JOBS     |  19 | 513 |   2   (0)| 00:00:01 |
|   5 |      INDEX FULL SCAN       | JOB_ID_PK   |  19 |     |   1   (0)| 00:00:01 |

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|*  6 |     SORT JOIN       |     | 107 | 2140 |   4  (25)| 00:00:01 |
|   7 |      TABLE ACCESS FULL       | EMPLOYEES   | 107 | 2140 |   3   (0)| 00:00:01 |
|   8 |    TABLE ACCESS FULL       | DEPARTMENTS |  27 | 432 |   3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

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

   2 - access("EMPLOYEES"."DEPARTMENT_ID"="DEPARTMENTS"."DEPARTMENT_ID")
   6 - access("EMPLOYEES"."JOB_ID"="JOBS"."JOB_ID")
       filter("EMPLOYEES"."JOB_ID"="JOBS"."JOB_ID")

22 rows selected.

3.解釋執行計劃:

(1).縮進越多的訪問路徑越先被執行。

(2)縮進到同樣級別的步驟,先執行最上面的那條語句。

4.虛擬索引(Vitual index)是指沒有創建對應的物理實體的索引。虛擬索引的目的,是在不必耗時,耗CPU,耗IO以及消耗大量存儲空間區實際創建的索引的情況下,來判斷一個索引是否能夠對SQL優化起到作用。

SQL> explain plan for select * from sh.sales where amount_sold >1000;

Explained.

SQL> select * from table(dbms_xplan.display(null,null,'TYPICAL'));

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Plan hash value: 1550251865

---------------------------------------------------------------------------------------------
| Id  | Operation    | Name  | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |    | 404K| 11M| 526   (2)| 00:00:01 |    |    |
|   1 |  PARTITION RANGE ALL|    | 404K| 11M| 526
  (2)| 00:00:01 |  1 | 28 |
|*  2 |   TABLE ACCESS FULL | SALES | 404K| 11M| 526   (2)| 00:00:01 |  1 | 28 |
---------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
---------------------------------------------------

   2 - filter("AMOUNT_SOLD">1000)

14 rows selected.


建虛擬索引:

SQL> alter session set "_use_nosegment_indexes"=TRUE;

Session altered.

SQL> create index sh.sales_vit on sh.sales(amount_sold) nosegment;

Index created.


SQL> select * from table(dbms_xplan.display(null,null,'TYPICAL'));


PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1798903108


----------------------------------------------------------------------------------------------------------------
| Id  | Operation   | Name      | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |   404K|    11M|   366 (0)| 00:00:01 |       |       |
|   1 |  TABLE ACCESS BY GLOBAL INDEX ROWID| SALES     |   404K|    11M|   366 (0)| 00:00:01 | ROWID | ROWID |
|*  2 |   INDEX RANGE SCAN   | SALES_VIT |   404K|       |    13 (0)| 00:00:01 |       |       |
----------------------------------------------------------------------------------------------------------------


Predicate Information (identified by operation id):


PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------

   2 - access("AMOUNT_SOLD">1000)

14 rows selected.

本例中如果建立索引是有用的,優化器估算的成本從526降366,因此在不創建索引的情況下,可以使用虛擬索引來確定優化器是否應該使用索引。


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