2014-12-19 Created By BaoXinjian
一、摘要
在SQL語句的執行計划中,包含很多字段項和很多模塊,其不同字段代表了不同的含義且在不同的情形下某些字段、模塊顯示或不顯示,下
面的描述給出了執行計划中各字段的含義以及各模塊的描述。
二、執行計划分析過程
1. 分析解析計划
Step1. 打開熟悉的查看工具:PL/SQL Developer - Toad。
在PL/SQL Developer中寫好一段SQL代碼后,按F5,PL/SQL Developer會自動打開執行計划窗口,顯示該SQL的執行計划。
Step2. 查看總COST,獲得資源耗費的總體印象
一般而言,執行計划第一行所對應的COST(即成本耗費)值,反應了運行這段SQL的總體估計成本,單看這個總成本沒有實際意義,
但可以拿它與相同邏輯不 同執行計划的SQL的總體COST進行比較,通常COST低的執行計划要好一些。
Step3. 按照從左至右,從上至下的方法,了解執行計划的執行步驟
執行計划按照層次逐步縮進,從左至右看,縮進最多的那一步,最先執行,如果縮進量相同,則按照從上而下的方法判斷執行順序,可粗略認為上面的步驟優先執行。
每一個執行步驟都有對應的COST,可從單步COST的高低,以及單步的估計結果集(對應ROWS/基數),來分析表的訪問方式,連接順序以及連接方式是 否合理。
Step4. 分析表的訪問方式
表的訪問方式主要是兩種:
全表掃描(TABLE ACCESS FULL)和索引掃描(INDEX SCAN),如果表上存在選擇性很好的索引,卻走了全表掃描,而且是大表的全表掃描,就說明表的訪問方式可能存在問題;
若大表上沒有合適的索引而走了全表 掃描,就需要分析能否建立索引,或者是否能選擇更合適的表連接方式和連接順序以提高效率。
Step5. 分析表的連接方式和連接順序
表的連接順序:就是以哪張表作為驅動表來連接其他表的先后訪問順序。
表的連接方式:簡單來講,就是兩個表獲得滿足條件的數據時的連接過程。
主要有三種表連接方式,嵌套循環(NESTED LOOPS)、哈希連接(HASH JOIN)和排序-合並連接(SORT MERGE JOIN)。我們常見得是嵌套循環和哈希連接。
嵌套循環:
最適用也是最簡單的連接方式。類似於用兩層循環處理兩個游標,外層游標稱作驅動表,Oracle檢索驅動表的數據,一條一條的代入內層游標,查找滿足WHERE條件的所有數據,因此內層游標表中可用索引的選擇性越好,嵌套循環連接的性能就越高。
哈希連接:
先將驅動表的數據按照條件字段以散列的方式放入內存,然后在內存中匹配滿足條件的行。
哈希連接需要有合適的內存,而且必須在CBO優化模式下,連接兩表的WHERE條件有等號的情況下才可以使用。哈希連接在表的數據量較大,表中沒有合適的索引可用時比嵌套循環的效率要高。
2. 總結兩點:
2.1 這里看到的執行計划,只是SQL運行前可能的執行方式,實際運行時可能因為軟硬件環境的不同,而有所改變,而且cost高的執行計划,不一定在實際運行起來,速度就一定差,我們平時需要結合執行計划,和實際測試的運行時間,來確定一個執行計划的好壞。
2.2 對於表的連接順序,多數情況下使用的是嵌套循環,尤其是在索引可用性好的情況下,使用嵌套循環式最好的,但當ORACLE發現需要訪問的數據表較大,索引 的成本較高或者沒有合適的索引可用時,會考慮使用哈希連接,以提高效率。排序合並連接的性能最差,但在存在排序需求,或者存在非等值連接無法使用哈希連接 的情況下,排序合並的效率,也可能比哈希連接或嵌套循環要好。
三、執行計划中各字段的描述
1. 基本字段(總是可用的)
- Id 執行計划中每一個操作(行)的標識符。如果數字前面帶有星號,意味着將在隨后提供這行包含的謂詞信息
- Operation 對應執行的操作。也叫行源操作
- Name 操作的對象名稱
2. 查詢優化器評估信息
- Rows(E-Rows) 預估操作返回的記錄條數
- Bytes(E-Bytes) 預估操作返回的記錄字節數
- TempSpc 預估操作使用臨時表空間的大小
- Cost(%CPU) 預估操作所需的開銷。在括號中列出了CPU開銷的百分比。注意這些值是通過執行計划計算出來的。換句話說,父操作的開銷包含子操作的開銷
- Time 預估執行操作所需要的時間(HH:MM:SS)
3. 分區(僅當訪問分區表時下列字段可見)
- Pstart 訪問的第一個分區。如果解析時不知道是哪個分區就設為KEY,KEY(I),KEY(MC),KEY(OR),KEY(SQ)
- Pstop 訪問的最后一個分區。如果解析時不知道是哪個分區就設為KEY,KEY(I),KEY(MC),KEY(OR),KEY(SQ)
4. 並行和分布式處理(僅當使用並行或分布式操作時下列字段可見)
- Inst 在分布式操作中,指操作使用的數據庫鏈接的名字
- TQ 在並行操作中,用於從屬線程間通信的表隊列
- IN-OUT 並行或分布式操作間的關系
- PQ Distrib 在並行操作中,生產者為發送數據給消費者進行的分配
5. 運行時統計(當設定參數statistics_level為all或使用gather_plan_statistics提示時,下列字段可見)
- Starts 指定操作執行的次數
- A-Rows 操作返回的真實記錄數
- A-Time 操作執行的真實時間(HH:MM:SS.FF)
6. I/O 統計(當設定參數statistics_level為all或使用gather_plan_statistics提示時,下列字段可見)
- Buffers 執行期間進行的邏輯讀操作數量
- Reads 執行期間進行的物理讀操作數量
- Writes 執行期間進行的物理寫操作數量
7. 內存使用統計
- OMem 最優執行所需內存的預估值
- 1Mem 一次通過(one-pass)執行所需內存的預估值
- 0/1/M 最優/一次通過/多次通過(multipass)模式操作執行的次數
- Used-Mem 最后一次執行時操作使用的內存量
- Used-Tmp 最后一次執行時操作使用的臨時空間大小。這個字段必須擴大1024倍才能和其他衡量內存的字段一致(比如,32k意味着32MB)
- Max-Tmp 操作使用的最大臨時空間大小。這個字段必須擴大1024倍才能和其他衡量內存的字段一致(比如,32k意味着32MB)
四、執行計划中各模塊的描述與舉例
1. 執行前,系統預估解析計划,Explain Plan
SQL> explain plan for 02. 2 select * from emp e,dept d 03. 3 where e.deptno=d.deptno 04. 4 and e.ename='SMITH'; 05. 06.Explained.
15. 16.SQL> set linesize 180 17.SQL> set pagesize 0 18.SQL> select * from table(dbms_xplan.display(null,null,'advanced')); --使用dbms_xplan.display函數獲得語句的執行計划 19.Plan hash value: 351108634 --SQL語句的哈希植 20. 21.---------------------------------------------------------------------------------------- /*執行計划部分*/ 22.| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | 23.---------------------------------------------------------------------------------------- 24.| 0 | SELECT STATEMENT | | 1 | 117 | 4 (0)| 00:00:01 | 25.| 1 | NESTED LOOPS | | 1 | 117 | 4 (0)| 00:00:01 | 26.|* 2 | TABLE ACCESS FULL | EMP | 1 | 87 | 3 (0)| 00:00:01 | 27.| 3 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 30 | 1 (0)| 00:00:01 | 28.|* 4 | INDEX UNIQUE SCAN | PK_DEPT | 1 | | 0 (0)| 00:00:01 | 29.---------------------------------------------------------------------------------------- 30. 31.Query Block Name / Object Alias (identified by operation id): --這部分顯示的為查詢塊名和對象別名 32.------------------------------------------------------------- 33. 34. 1 - SEL$1 --SEL$為select 的縮寫,位於塊1,相應的還有DEL$,INS$,UPD$等 35. 2 - SEL$1 / E@SEL$1 --E@SEL$1,對應到執行計划中的操作ID為2上,即在表E上的查詢,E為別名,下面類同 36. 3 - SEL$1 / D@SEL$1 37. 4 - SEL$1 / D@SEL$1 38. 39.Outline Data --提綱部分,這部分將執行計划中的圖形化方式以文本形式來呈現,即轉換為提示符方式 40.------------- 41. 42. /*+ 43. BEGIN_OUTLINE_DATA 44. USE_NL(@"SEL$1" "D"@"SEL$1") --使用USE_NL提示,即嵌套循環 45. LEADING(@"SEL$1" "E"@"SEL$1" "D"@"SEL$1") --指明前導表 46. INDEX_RS_ASC(@"SEL$1" "D"@"SEL$1" ("DEPT"."DEPTNO")) --指明對於D上的訪問方式為使用索引 47. FULL(@"SEL$1" "E"@"SEL$1") --指明對於E上的訪問方式為全表掃描 48. OUTLINE_LEAF(@"SEL$1") 49. ALL_ROWS 50. OPTIMIZER_FEATURES_ENABLE('10.2.0.3') 51. IGNORE_OPTIM_EMBEDDED_HINTS 52. END_OUTLINE_DATA 53. */ 54. 55.Predicate Information (identified by operation id): --謂詞信息部分,在執行計划中ID帶有星號的每一行均對應到下面中的一行 56.--------------------------------------------------- 57. 58. 2 - filter("E"."ENAME"='SMITH') 59. 4 - access("E"."DEPTNO"="D"."DEPTNO") 60. 61.Column Projection Information (identified by operation id): --執行時每一步驟所返回的列,下面的不同步驟返回了不同的列 62.----------------------------------------------------------- 63. 64. 1 - (#keys=0) "E"."EMPNO"[NUMBER,22], "E"."ENAME"[VARCHAR2,10], 65. "E"."JOB"[VARCHAR2,9], "E"."MGR"[NUMBER,22], "E"."HIREDATE"[DATE,7], 66. "E"."SAL"[NUMBER,22], "E"."COMM"[NUMBER,22], "E"."DEPTNO"[NUMBER,22], 67. "D"."DEPTNO"[NUMBER,22], "D"."DNAME"[VARCHAR2,14], "D"."LOC"[VARCHAR2,13] 68. 2 - "E"."EMPNO"[NUMBER,22], "E"."ENAME"[VARCHAR2,10], "E"."JOB"[VARCHAR2,9], 69. "E"."MGR"[NUMBER,22], "E"."HIREDATE"[DATE,7], "E"."SAL"[NUMBER,22], 70. "E"."COMM"[NUMBER,22], "E"."DEPTNO"[NUMBER,22] 71. 3 - "D"."DEPTNO"[NUMBER,22], "D"."DNAME"[VARCHAR2,14], "D"."LOC"[VARCHAR2,13] 72. 4 - "D".ROWID[ROWID,10], "D"."DEPTNO"[NUMBER,22] 73. 74.Note --注釋與描述部分,下面的描述中給出了本次SQL語句使用了動態采樣功能 75.----- 76. - dynamic sampling used for this statement 77. 78.58 rows selected.
2. 執行后,系統實際解析計划,Explain Plan
SQL> select /*+ gather_plan_statistics */ * --注意此處增加了提示gather_plan_statistics並且該語句被執行
02. 2 from emp e,dept d 03. 3 where e.deptno=d.deptno 04. 4 and e.ename='SMITH'; 05. 06. 7369 SMITH CLERK 7902 17-DEC-80 800 20 20 RESEARCH DALLAS 07. 08.SQL> select * from table(dbms_xplan.display_cursor(null,null,'iostats last')); --使用display_cursor獲取實際的執行計划
09. 10.SQL_ID fpx7zw59f405d, child number 0 --這部分給出了SQL語句的SQL_ID,子游標號以及原始的SQL語句
11.-------------------------------------
12.select /*+ gather_plan_statistics */ * from emp e,dept d where e.deptno=d.deptno and
13.e.ename='SMITH'
14. 15.Plan hash value: 351108634 --SQL 語句的哈希值
16. --SQL語句的執行計划,可以看到下面顯示的字段一部分不同於預估執行計划中的字段
17.-----------------------------------------------------------------------------------------------------------
18.| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
19.-----------------------------------------------------------------------------------------------------------
20.| 1 | NESTED LOOPS | | 1 | 1 | 1 |00:00:00.01 | 10 | 1 |
21.|* 2 | TABLE ACCESS FULL | EMP | 1 | 1 | 1 |00:00:00.01 | 8 | 0 |
22.| 3 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 1 | 1 |00:00:00.01 | 2 | 1 |
23.|* 4 | INDEX UNIQUE SCAN | PK_DEPT | 1 | 1 | 1 |00:00:00.01 | 1 | 1 |
24.-----------------------------------------------------------------------------------------------------------
25. 26.Predicate Information (identified by operation id): 27.---------------------------------------------------
28. 29. 2 - filter("E"."ENAME"='SMITH') 30. 4 - access("E"."DEPTNO"="D"."DEPTNO") 31. 32.Note 33.-----
34. - dynamic sampling used for this statement 35. 36. 37.26 rows selected.
Thank and Regards
轉載:樂沙彌 - http://blog.csdn.net/leshami/article/details/6860007