Oracle執行計劃學習筆記
目錄
- 一、獲取執行計劃的方法
- (1) explain plan for
- (2) set autotrace on
- (3) statistics_level=all
- (4) dbms_xplan.display_cursor獲取
- (5) 事件10046 trace跟蹤
- (6) awrsqrpt.sql
- 二、解釋經典執行計劃的方法
- 【單獨型】
- 【聯合型關聯型】
- 【聯合型非關聯型】
最近拜讀《收獲,不止SQL優化》一書,並做了筆記,方便自己以後回顧,同時放在網上或許也有益於別人
一、獲取執行計劃的方法
(1) explain plan for
步驟:
- 1:explain plan for 你的SQL;
- 2:select * from table (dbms_xplan. display()) ;
- 優點:不需要真的執行,快捷方便
- 缺點:沒有輸出運行時的統計信息(邏輯讀、遞歸調用,物理讀),因為沒有真正執行,所以不能看到執行了多少行、表被訪問了多少次等等
(2) set autotrace on
sqlplus登錄:
用戶名/密碼@主機名稱:1521/數據庫名
步驟:
- 1:set sutoatrace on
- 2:在此次執行你的sql;
- 優點:可以看到運行時的統計信息(邏輯讀、遞歸調用,物理讀)
- 缺點:不能看到表被訪問了多少次,也需要等sql執行完成才能看
(3) statistics_level=all
步驟:
- 1:alter session set statistics_level=all;
- 2:在此處執行你的SQL;
- 3:select * from table(dbms_xplan.display_cursor(null , null,‘allstats last‘));
假如使用了Hint語法: /+ gather_plan_statistics
關鍵字解讀:
- Starts:該SQL執行的次數
- E-Rows:為執行計劃預計的行數
- A-Rows:實際返回的行數,E-Rows和A-Rows作比較,就可以看出具體那一步執行計劃出問題了
- A-Time:每一步實際執行的時間,可以看出耗時的SQL
- Buffers:每一步實際執行的邏輯讀或一致性讀
- Reads:物理讀
- OMem:當前操作完成所有內存工作區操作總使用私有內存工作區(PGA)的大小
- lMem:當工作區大小無法符滿足操作需求的大小時,需要將部分數據寫入臨時磁盤空間中(如果僅需要寫入一次就可以完成操作,就稱一次通過,One-Pass;否則為多次通過,Multi-Pass)。改數據為語句最後一次執行中,單次寫磁盤所需要的內存大小,這個是由優化器統計數據以及前一次執行的性能數據估算得出的
- Used-Mem:語句最後一次執行中,當前操作所使用的內存工作區大小,括號裏面為(發生磁盤交換的次數,1次即為One-Pass,大於一次則為Mullti-Pass,如果沒有使用磁盤,則顯示為OPTI1MAL)
OMem、lMem為執行所需要的內存評估值,OMem為最優執行模式所需要內存的評估值,Used-Mem為消耗的內存
優點:
- 可以從STARTS得出表被訪問多少次;
- 可以清晰地從E-ROWS和A-ROWS中分別得出預測的行數和真實的行數
缺點: - 必須等到語句真正執行完成後,才可以得出結果
- 無法控制記錄打屏輸出,不想aututrace有traceonly命令
- 沒有專門的輸出統計信息,看不到遞歸調用的次數,看不出物理讀具體數值,不過有邏輯讀,邏輯讀才是重點
(4) dbms_xplan.display_cursor獲取
步驟
從共享池獲取
//${SQL_ID}參數可以從共享池拿
select * from table(dbms_xplan.display_cursor(${SQL_ID}));
還可以從AWR性能視圖裏獲取
select * from table(dbms_xplan.display_awr(${SQL_ID}));
多個執行計劃的情況,可以用類似方法查出
select * from table(dbms_xplan.display_cursor(${SQL_ID},0));
select * from table(dbms_xplan.display_cursor(${SQL_ID},1));
優點:
- 和explain一樣不需要真正執行,知道sql_id就好
缺點:
- 不能判斷處理了多少行
- 無法判斷表被訪問了多少次
- 沒有輸出運行時的相關統計信息(邏輯讀、遞歸調用、物理讀)
(5) 事件10046 trace跟蹤
步驟:
1:alter session set events '10046 trace name context forever,level 12';//開啟跟蹤
2:執行你的語句
3:alter session set events '10046 trace name context off';//關閉跟蹤
4:找到跟蹤產生的文件
5:tkprof trc文件 目標文件 sys=no sort=prsela,exeela,fchela(格式化命令)
優點:
- 可以看出SQL語句對應的等待事件
- 可以列出sql語句中的函數調用的
- 可以看出解析事件和執行事件
- 可以跟蹤整個程序包
- 可以看出處理的行數,產生的邏輯讀
缺點: - 步驟比較繁瑣
- 無法判斷表被訪問了多少次
- 執行計劃中的謂詞部分不能清晰地顯示出來
(6) awrsqrpt.sql
步驟:
1:@?/rdbms/admin/awrsqrpt.sql
具體可以參考我之前的博客:https://smilenicky.blog.csdn.net/article/details/89429989
二、解釋經典執行計劃的方法
可以分為兩種類型:單獨型和聯合型
聯合型分為:關聯的聯合型和非關聯的聯合型
【單獨型】
單獨型比較好理解,執行順序是按照id=1,id=2,id=3執行,由遠及近
先scott登錄,然後執行sql,例子來自《收獲,不止SQL優化》一書
select deptno, count(*)
from emp
where job = 'CLERK'
and sal < 3000
group by deptno
所以可以給出單獨型的圖例:
【聯合型關聯型】
(1) 聯合型的關聯型(NL)
這裏使用Hint的nl
select /*+ ordered use_nl(dept) index(dept) */ *
from emp, dept
where emp.deptno = dept.deptno
and emp.comm is null
and dept.dname != 'SALES'
這圖來自《收獲,不止SQL優化》,可以看出id為2的A-Rows實踐返回行數為10,id為3的Starts為10,說明驅動表emp訪問的結果集返回多少條記錄,被驅動表就被訪問多少次,這是關聯型的顯著特征
關聯型不一定是驅動表返回多少條,被驅動表就被訪問多少次的,註意FILTER模式也是關聯型的
(2) 聯合型的關聯型(FILTER)
前面已經介紹了聯合型關聯型(nl)這種方法的,這種方法是驅動表返回多少條記錄,被驅動表就被訪問了多少次,不過這種情況對於FILTER模式下並不適用
執行SQL,這裏使用Hint /+ no_unnset /
select * from emp where not exists (select /*+ no_unnset */ 0 from dept
where dept.dname='SALES' and dept.deptno = emp.deptno) and not exists(select /*+ no_unnset */ 0 from bonus where bonus.ename = emp.ename)
ps:圖來自《收獲,不止SQL優化》一書,這裏可以看出id為2的地方,A-Rows實際返回行數為8,而id為3的地方,Starts為3,說明對應SQL執行3次,也即dept被驅動表被訪問了3次,這和剛才介紹的nl方式不同,為什麽不同?
查詢一下SQL,可以看出實際返回3條,其它的都是重復多的,
select dname, count(*) from emp, dept where emp.deptno = dept.deptno group by dname;
所以,就很明顯了,被過濾了重復數據,也就是說FILTER模式的對數據進行過濾,驅動表執行結果集返回多少行不重復數據,被驅動表就被訪問多少次,FILTER模式可以說是對nl模式的改善
(3) 聯合型的關聯型(UPDATE)
update emp e1 set sal = (select avg(sal) from emp e2 where e2.deptno = e1.deptno),comm = (select avg(comm) from emp e3)
聯合型的關聯型(UPDATE)和FILTER模式類似,所以就不重復介紹
(4) 聯合型的關聯型(CONNECT BY WITH FILTERING)
select /*+ connect_by_filtering */ level, ename ,prior
ename as manager from emp start with mgr is null connect by prior empno = mgr
給出聯合型關聯型圖例:
【聯合型非關聯型】
可以執行SQL
select ename from emp union all select dname from dept union all select '%' from dual
對於plsql可以使用工具查看執行計劃,sqlplus客戶端的可以使用statistics_level=all的方法獲取執行計劃,具體步驟
- 1:alter session set statistics_level=all;
- 2:在此處執行你的SQL;
- 3:select * from table(dbms_xplan.display_cursor(null , null,‘allstats last‘));
可以給出聯合型非關聯型的圖例:
Oracle執行計劃學習筆記