本文所涉及實驗內容均來自版本11.2.0.4,以下內容為個人整理,僅用於記錄與交流,切記任何實驗內容請勿在生產庫上進行實驗!請珍惜DBA職業生涯!轉載注明出處。 |
在SQL優化的工作中,大部分的情況就是對SQL的執行計划進行調整,本編文章是我在回顧獲取SQL執行計划時所整理,如有不足之處,歡迎指正。
●SQL_TRACE
●10046事件
●explain plan
●DBMS_XPLAN
●AUTOTRACE開關
1、SQL_TRACE
SQL_TRACE工具可以在會話級別和全局級別進行使用,在全局級別使用時會造成系統資源的過度消耗,請謹慎使用,會話級別的跟蹤足以滿足獲取目標SQL執行計划的需求。
下面的實驗是在當前會話級別設置跟蹤。
SYS@tank> alter session set sql_trace=true;
Session altered.
SYS@tank> select * from scott.emp where mgr='7902';
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17-DEC-80 800 (null) 20
SYS@tank> alter session set events '10046 trace name context off';
Session altered.
SYS@tank> select * from v$diag_info where NAME='Default Trace File';
INST_ID NAME VALUE
---------- --------- --------------------------
1 Default Trace File /u01/app/oracle/diag/rdbms/tank/tank/trace/tank_ora_46538.trc
*** 2017-02-13 06:14:26.988
CLOSE #140260733475704:c=0,e=36,dep=0,type=0,tim=1486937666988561
=====================
PARSING IN CURSOR #140260733475704 len=40 dep=0 uid=0 oct=3 lid=0 tim=1486937666989008 hv=1742497264 ad='b8f3a058' sqlid='8rz
uygtmxstgh'
select * from scott.emp where mgr='7902'
END OF STMT
PARSE #140260733475704:c=0,e=121,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1491239009,tim=1486937666988985
EXEC #140260733475704:c=0,e=154,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1491239009,tim=1486937666989267
FETCH #140260733475704:c=3000,e=2080,p=0,cr=2,cu=0,mis=0,r=1,dep=0,og=1,plh=1491239009,tim=1486937666991546
FETCH #140260733475704:c=0,e=78,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1491239009,tim=1486937666993344
STAT #140260733475704 id=1 cnt=1 pid=0 pos=1 obj=87108 op='TABLE ACCESS BY INDEX ROWID EMP (cr=2 pr=0 pw=0 time=199 us cost=2
size=87 card=1)'
STAT #140260733475704 id=2 cnt=1 pid=1 pos=1 obj=88613 op='INDEX RANGE SCAN INDX_MGR (cr=1 pr=0 pw=0 time=100 us cost=1 size=
0 card=1)'
可以發現以上信息閱讀起來不是很方便,在這里使用tkprof命令對trc文件進行格式化再進行查看。
[oracle@tank ~]$ tkprof /u01/app/oracle/diag/rdbms/tank/tank/trace/tank_ora_46538.trc output.txt
TKPROF: Release 11.2.0.4.0 - Development on Mon Feb 13 06:17:29 2017
Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.
查看格式化后的output.txt文件末端的信息即可查看目標SQL的執行計划及相關詳細信息。
********************************************************************************
SQL ID: 8rzuygtmxstgh Plan Hash: 1491239009
select *
from
scott.emp where mgr='7902'
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 3 0.04 0.04 18 108 0 0
Execute 3 0.00 0.00 0 0 0 0
Fetch 6 0.00 0.00 0 6 0 3
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 12 0.05 0.05 18 114 0 3
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: SYS
Number of plan statistics captured: 3
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 TABLE ACCESS BY INDEX ROWID EMP (cr=2 pr=0 pw=0 time=294 us cost=2 size=87 card=1)
1 1 1 INDEX RANGE SCAN INDX_MGR (cr=1 pr=0 pw=0 time=97 us cost=1 size=0 card=1)(object id 88613
)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
db file sequential read 4 0.00 0.00
SQL*Net message to client 4 0.00 0.00
SQL*Net message from client 4 7.55 13.79
********************************************************************************
如果想跟蹤其他用戶進程,需用到dbms_system包來完成,此處不做演示。
2、10046事件
10046事件相對比其他的執行計划獲取方式,這種方法所得到執行計划的內容更為詳細,針對性較強,尤其是在SQL性能分析中幫助很大,所得到的執行計划中明確顯示了目標SQL實際執行中每一個執行步驟所消耗的邏輯讀、物理讀以及所花費的時間。
在以下調試級別中Level 12使用頻率較高,11g在此基礎上增加了幾個調試級別,各級別向下兼容,可自行學習。
●Level 1:跟蹤SQL語句,包括解析、執行、提取、提交和回滾等。等價於啟用標准的SQL_TRACE功能。
●Level 4:Level 1+綁定變量的詳細信息。
●Level 8:Level 1+等待時間跟蹤。
●Level 12:Level 4+ Level 8。
10046時間可以在全局進級別(修改參數文件)行設置也可以在會話級別進行設置,使用全局設置的情況不多,下面將演示的是在會話級別獲取SQL的執行計划。
SYS@tank> alter session set events '10046 trace name context forever,level 12';
Session altered.
SYS@tank> select * from scott.emp where mgr='7902';
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17-DEC-80 800 (null) 20
SYS@tank> alter session set events '10046 trace name context off';
Session altered.
SYS@tank> select * from v$diag_info where NAME='Default Trace File';
INST_ID NAME VALUE
------------- --------- -------------------------------------------------
1 Default Trace File /u01/app/oracle/diag/rdbms/tank/tank/trace/tank_ora_43934.trc
同樣使用tkprof命令對trc文件進行格式化再進行查看。
[oracle@tank ~]$ tkprof /u01/app/oracle/diag/rdbms/tank/tank/trace/tank_ora_43934.trc output.txt
TKPROF: Release 11.2.0.4.0 - Development on Mon Feb 13 05:45:27 2017
Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.
查看output.txt格式化文件末端的信息即可查看目標SQL的執行計划及相關詳細信息。
********************************************************************************
SQL ID: 8rzuygtmxstgh Plan Hash: 1491239009
select *
from
scott.emp where mgr='7902'
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 2 0.04 0.04 18 108 0 0
Execute 2 0.00 0.00 0 0 0 0
Fetch 4 0.00 0.00 0 4 0 2
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 8 0.05 0.04 18 112 0 2
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: SYS
Number of plan statistics captured: 2
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 TABLE ACCESS BY INDEX ROWID EMP (cr=2 pr=0 pw=0 time=342 us cost=2 size=87 card=1)
1 1 1 INDEX RANGE SCAN INDX_MGR (cr=1 pr=0 pw=0 time=96 us cost=1 size=0 card=1)(object id 88613
)
Elapsed times include waiting on following events:
Event waited on Times Max. Wait Total Waited
---------------------------------------- Waited ---------- ------------
db file sequential read 4 0.00 0.00
SQL*Net message to client 4 0.00 0.00
SQL*Net message from client 4 7.55 13.79
********************************************************************************
3、explain plan
在執行explain plan命令時,Oracle 10g以上版本會將目標SQL產生的執行計划的具體執行步驟寫入到PLAN_TABLE$中,然后通過查詢語句“select * from table(dbms_xplan.display);”從PLAN_TABLE$中將執行步驟以格式化的方式顯示出來,PLAN_TABLE$是會話級臨時表,各個會話互不干擾,只能查看自己的執行SQL所產生的執行計划。
PL/SQL developer中F5快捷鍵(獲取SQL執行計划)封裝的就是explain plan。
SYS@tank> explain plan for select * from scott.emp where mgr='7902';
Explained.
SYS@tank> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
Plan hash value: 1491239009
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 87 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 87 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | INDX_MGR | 1 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("MGR"=7902)
Note
-----
- dynamic sampling used for this statement (level=2)
18 rows selected.
4、DBMS_XPLAN包
SYS@tank> select * from scott.emp where mgr='7902';
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17-DEC-80 800 (null) 20
執行目標SQL后緊跟着以下語句進行查詢執行計划。
SYS@tank> select * from table(dbms_xplan.display_cursor(null,null,'advanced'));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------
SQL_ID 8rzuygtmxstgh, child number 1
-------------------------------------
select * from scott.emp where mgr='7902'
Plan hash value: 1491239009
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 87 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | INDX_MGR | 1 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1 / EMP@SEL$1
2 - SEL$1 / EMP@SEL$1
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('11.2.0.4')
DB_VERSION('11.2.0.4')
ALL_ROWS
OUTLINE_LEAF(@"SEL$1")
INDEX_RS_ASC(@"SEL$1" "EMP"@"SEL$1" ("EMP"."MGR"))
END_OUTLINE_DATA
*/
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("MGR"=7902)
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - "EMP"."EMPNO"[NUMBER,22], "EMP"."ENAME"[VARCHAR2,10],
"EMP"."JOB"[VARCHAR2,9], "MGR"[NUMBER,22], "EMP"."HIREDATE"[DATE,7],
"EMP"."SAL"[NUMBER,22], "EMP"."COMM"[NUMBER,22], "EMP"."DEPTNO"[NUMBER,22]
2 - "EMP".ROWID[ROWID,10], "MGR"[NUMBER,22]
Note
-----
- dynamic sampling used for this statement (level=2)
51 rows selected.
如果將第三個傳入值“ADVANCED”替換成“ALL”,輸出結果中將不顯示Outline Data內容。
5、AUTOTRACE開關
使用AUTOTRACE開關出了獲取目標SQL執行計划外,還能額外觀察到目標SQL執行時所耗費的物理讀、邏輯讀、產生REDO的數量以及排序的數量等。
SYS@tank> set autotrace on
SYS@tank> select * from scott.emp where mgr='7902';
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
7369 SMITH CLERK 7902 17-DEC-80 800 (null) 20
Execution Plan
----------------------------------------------------------
Plan hash value: 1491239009
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 87 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 87 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | INDX_MGR | 1 | | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("MGR"=7902)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
1025 bytes sent via SQL*Net to client
524 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
AUTOTRACE開關有如下幾種參數可以設置:
set autotrace on --三個部分:執行結果、執行計划、統計信息
set autotrace traceonly --兩個部分:執行計划和統計信息
set autotrace traceonly explain --只看執行計划
set autotrace traceonly statistics --只看統計信息
以上5項內容是學習查看SQL的執行計划簡單整理,后續會根據實際使用情況做進一步補充與修改,如有描述不妥,歡迎指正。
參考資料:《基於Oracle的SQL優化》-崔華 P85-P203
《深入解析Oracle:DBA入門、進階與診斷案例》-蓋國強 P479-P488
-The end-
Tank
20170220