1. 程式人生 > >Oracle執行計劃學習筆記

Oracle執行計劃學習筆記

pga ceo nag csdn 工作區 lis png class set

目錄

  • 一、獲取執行計劃的方法
    • (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

/,就可以省略步驟1,直接執行步驟2和3,獲取執行計劃

關鍵字解讀:

  • 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執行計劃學習筆記