【優化】Oracle 執行計劃
1,什麼是執行計劃
所謂執行計劃,顧名思義,就是對一個查詢任務,做出一份怎樣去完成任務的詳細方案。舉個生活中的例子,我從珠海要去英國,我可以
選擇先去香港然後轉機,也可以先去北京轉機,或者去廣州也可以。但是到底怎樣去英國划算,也就是我的費用最少,這是一件值得考究
的事情。同樣對於查詢而言,我們提交的SQL僅僅是描述出了我們的目的地是英國,但至於怎麼去,通常我們的SQL中是沒有給出提示資訊
的,是由資料庫來決定的。
我們先簡單的看一個執行計劃的對比:
SQL> set autotrace traceonly
執行計劃一:
SQL> select count(*) from t;
COUNT(*)
----------
24815
Execution Plan
0 SELECT STATEMENT ptimizer=CHOOSE
1 0 SORT (AGGREGATE)
2 1 TABLE Access (FULL) OF 'T'
執行計劃二:
SQL> select count(*) from t;
COUNT(*)
24815
Execution Plan
0 SELECT STATEMENT ptimizer=CHOOSE (Cost=26 Card=1)
1 0 SORT (AGGREGATE)
2 1 INDEX (FULL SCAN) OF 'T_INDEX' (NON-UNIQUE) (Cost=26 Card=28180)
這兩個執行計劃中,第一個表示求和是通過進行全表掃描來做的,把整個表中資料讀入記憶體來逐條累加;第二個表示根據表中索引,把
整個索引讀進記憶體來逐條累加,而不用去讀表中的資料。但是這兩種方式到底哪種快呢?通常來說可能二比一快,但也不是絕對的。這是一
個很簡單的例子演示執行計劃的差異。對於複雜的SQL(表連線、巢狀子查詢等),執行計劃可能幾十種甚至上百種,但是到底那種最好呢?
我們事前並不知道,資料庫本身也不知道,但是資料庫會根據一定的規則或者統計資訊(statistics)去選擇一個執行計劃,通常來說選擇的是
比較優的,但也有選擇失誤的時候,這就是這次討論的價值所在。
Oracle優化器模式
Oracle優化器有兩大類,基於規則的和基於代價的,在SQLPLUS中我們可以檢視init檔案中定義的預設的優化器模式。
SQL> show parameters optimizer_mode
NAME TYPE VALUE
optimizer_mode string CHOOSE
SQL>
這是Oracle8.1.7 企業版,我們可以看出,預設安裝後資料庫優化器模式為CHOOSE,我們還可以設定為 RULE、
FIRST_ROWS,ALL_ROWS。可以在init檔案中對整個instance的所有會話設定,也可以單獨對某個會話設定:
SQL> ALTER SESSION SET optimizer_mode = RULE;
會話已更改。
SQL> ALTER SESSION SET optimizer_mode = FIRST_ROWS;
會話已更改。
SQL> ALTER SESSION SET optimizer_mode = ALL_ROWS;
會話已更改。
基於規則的查詢,資料庫根據表和索引等定義資訊,按照一定的規則來產生執行計劃;基於代價的查詢,資料庫根據蒐集的表和索引的
資料的統計資訊(通過analyze 命令或者使用dbms_stats包來蒐集)綜合來決定選取一個資料庫認為最優的執行計劃(實際上不一定最優)。
RULE是基於規則的,CHOOSE表示如果查詢的表存在蒐集的統計資訊則基於代價來執行(在CHOOSE模式下Oracle採用的是 FIRST_ROWS)
,否則基於規則來執行。在基於代價的兩種方式中,FIRST_ROWS指執行計劃採用最少資源儘快的返回部分結果給客戶端,對於排序分頁
頁顯示這種查詢尤其適用,ALL_ROWS指以總體消耗資源最少的方式返回結果給客戶端。
基於規則的模式下,資料庫的執行計劃通常比較穩定。但在基於代價的模式下,我們才有更大的機會選擇最優的執行計劃。也由於
Oracle的很多查詢方面的特性必須在基於代價的模式下才能體現出來,所以我們通常不選擇RULE(並且Oracle宣稱從 Oracle 10i版本資料庫
開始將不再支援 RULE)。既然是基於代價的模式,也就是說執行計劃的選擇是根據表、索引等定義和資料的統計資訊來決定的,這個統計
資訊是根據 analyze 命令或者dbms_stats包來定期蒐集的。首先存在著一種可能,就是由於蒐集資訊是一個很消耗資源和時間的動作,尤
其當表資料量很大的時候,因為蒐集資訊是對整個表資料進行重新的完全統計,所以這是我們必須慎重考慮的問題。我們只能在伺服器空
閒的時候定期的進行資訊蒐集。這說明我們在一段時期內,統計資訊可能和資料庫本身的資料並不吻合;另外就是Oracle的統計資料本身也
存在著不精確部分(詳細參考Oracle DOCUMENT),更重要的一個問題就是及時統計資料相對已經比較準確,但是Oracle的優化器的選擇也
並不是始終是最優的方案。這也倚賴於Oracle對不同執行計劃的代價的計算規則(我們通常是無法知道具體的計算規則的)。這好比我們決定
從香港還是從北京去英國,車票、機票等實際價格到底是怎麼核算出來的我們並不知道,或者說我們現在瞭解的價格資訊,在我們乘車前
往的時候,真實價格跟我們的預算已經發生了變化。所有的因素,都將影響我們的整個開銷。
執行計劃穩定效能帶給我們什麼
Oracle存在著執行計劃選擇失誤的可能。這也是我們經常遇見的一些現象,比如總有人說我的程式在測試資料庫中跑的很好,但在產
品資料庫上就是跑的很差,甚至後者硬體條件比前者還好,這到底是為什麼?硬體資源、統計資訊、引數設定都可能對執行計劃產生影響。
由於因素太多,我們總是對未來懷著一種莫名的恐懼,我的產品資料庫上線後到底跑的好不好?於是Oracle提供了一種穩定執行計劃的能力
,也就是把在測試環境中的執行良好的執行計劃所產生的OUTLINES移植到產品資料庫,使得執行計劃不會隨著其他因素的變化而變化。
那麼OUTLINES是什麼呢?先要介紹一個內容,Oracle提供了在SQL中使用HINTS來引導優化器產生我們想要的執行計劃的能力。這在
多表連線、複雜查詢中特別有效。HINTS的型別很多,可以設定優化器目標(RULE、CHOOSE、FIRST_ROWS、ALL_ROWS),可以指定表
連線的順序,可以指定使用哪個表的哪個索引等等,可以對SQL進行很多精細的控制。通過這種方式產生我們想要的執行計劃的這些
HINTS,Oracle可以儲存這些HINTS,我們稱之為OUTLINES。通過STORE OUTLINES可以使得我們擁有以後產生相同執行計劃的能力,也
就是使我們擁有了穩定執行計劃的能力。
這裡想給出一個附加的說明就是,實際上,我們通過工具改寫SQL,比如使用SQL EXPERT改寫後的SQL,這些不僅僅是加了HINTS
而且文字都已經發生了變化的SQL,也可以儲存OUTLINES,並可被應用到應用中。但這不是一定生效,我們必須測試檢查是否生效。但由
於就算給了錯誤的OUTLINES,資料庫在執行的時候,也只是忽略過去重新生成執行計劃而不會返回錯誤,所以我們才敢放心的這麼使用。
當然在Oracle文件中並沒有指明可以這樣做,文件中只是說明,如果存在OUTLINES的同時又在SQL中加了HINTS,則會使用OUTLINES而
忽略HINTS。這個功能在LECCO將釋出的產品中會使用這一功能,這樣可以將SQL EXPERT的改寫SQL的能力和穩定執行計劃的能力結合起
來,那麼我們就對不能更改原始碼的應用具有了相當強大的SQL優化能力。
也許我們會有疑問,假如穩定了執行計劃,那還蒐集統計資訊幹嗎?這是因為幾個原因造成的,首先,現在的執行計劃對於未來發生了
變化的資料未必就是合適的,存在著當前的執行計劃不滿足未來資料的變化後的效率,而新的統計資訊的情況下所產生的執行計劃也並不
是全部都合理的。那這個時候,我們可以採用新蒐集的統計資訊,但是卻對新統計資訊下不良的執行計劃採用Oracle提供的執行計劃穩定
性這個能力固定執行計劃,這樣結合起來我們可以建立滿意的高效的資料庫執行環境。
我們還需要關注的一個東西,Oracle提供的dbms_stats包除了具有蒐集統計資訊的能力,還具有把資料庫中統計資訊(statistics)
export/import的能力,還具有隻蒐集統計資訊而使得統計資訊不應用於資料庫的能力(把統計資訊蒐集到一個特定的表中而不是立即生效)
,在這個基礎上我們就可以把統計資訊export出來再import到一個測試環境中,再執行我們的應用,在測試環境中我們觀察最新的統計信
息會導致哪些執行計劃發生變化(DB EXPERT的Plan Version Tracer是模擬不同環境並自動檢查不同環境中執行計劃變化的工具),是變好了
還是變差了。我們可以把變差的這一部分在測試環境中使用hints或者利用工具(SQL EXPERT是在重寫SQL這一領域目前最強有力的工具)產
生良好的執行計劃的SQL,利用這些SQL可以產生OUTLINES,然後在產品資料庫應用最新的統計資訊的同時移植進這些OUTLINES。
最後說一下我們不得不使用執行計劃穩定效能力的場合。我們假定Oracle的優化器的選擇都是準確的,但是優化器選擇的基礎就是我
們的SQL,這些SQL才從根本上決定了執行效率,這是更重要的一個優化的環節。SQL是基礎(當然資料庫的設計是基礎的基礎),一個SQL寫
的好不好,就相當於我們同樣是要想去英國,但是我的起點在珠海,你的起點卻在西藏的最邊緣偏僻的一個地方,那不管你做怎樣的最優
路線選擇,你都不如我在珠海去英國所花費的代價小。
2,怎麼生成的
1.Explain plan
explain plan for
select * from aa;
檢視結果:
select * from table(dbms_xplan.display());
2.Autotrace Set timing on --記錄所用時間
Set autot trace --自動記錄執行計劃
3.SQL_TRACE
ORACLE SQL_TRACE
“SQL TRACE”是Oracle提供的用於進行SQL跟蹤的手段,是強有力的輔助診斷工具。在日常的資料庫問題診斷和解決中,“SQL TRACE”是
非常常用的方法。
一般,一次跟蹤可以分為以下幾步:
1、界定需要跟蹤的目標範圍,並使用適當的命令啟用所需跟蹤。
2、經過一段時間後,停止跟蹤。此時應該產生了一個跟蹤結果檔案。
3、找到跟蹤檔案,並對其進行格式化,然後閱讀或分析。
本文就“SQL TRACE”的這些使用作簡單探討,並通過具體案例對SQL_TRACE的使用進行說明。
3,怎麼檢視執行計劃
從Oracle10g開始,可以通過EXPLAIN PLAN FOR檢視DDL語句的執行計劃了。
在9i及以前版本,Oracle只能看到DML的執行計劃,不過從10g開始,通過EXPLAIN PLAN FOR的方式,已經可以看到DDL語句的執行計劃
了。
這對於研究CREATE TABLE AS SELECT、CREATE MATERIALIZED VIEW AS SELECT以及CREATE INDEX,ALTER INDEX REBUILD等語
句有很大的幫助。
舉個簡單的例子,Oracle的文件上對於索引的建立有如下描述:
The optimizer can use an existing index to build another index. This results in a much faster index build.
如果看不到DDL的執行計劃,只能根據執行時間的長短去猜測Oracle的具體執行計劃,但是這種方法沒有足夠的說服力。但是通過DDL的執
行計劃,就使得結果一目瞭然了。
SQL> CREATE TABLE T AS SELECT * FROM DBA_OBJECTS;
表已建立。
SQL> EXPLAIN PLAN FOR
2 CREATE INDEX IND_T_NAME ON T(OBJECT_NAME);
已解釋。
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------
Plan hash value: 3035241083
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------
| 0 | CREATE INDEX STATEMENT | | 57915 | 3732K| 75 (2)| 00:00:01 |
| 1 | INDEX BUILD NON UNIQUE| IND_T_NAME | | | | |
| 2 | SORT CREATE INDEX | | 57915 | 3732K| | |
| 3 | TABLE ACCESS FULL | T | 57915 | 3732K| 41 (3)| 00:00:01 |
-------------------------------------------------------------------------------------
Note
-----
- estimated index size: 5242K bytes
已選擇14行。
SQL> CREATE INDEX IND_T_OWNER_NAME ON T(OWNER, OBJECT_NAME);
索引已建立。
SQL> EXPLAIN PLAN FOR
2 CREATE INDEX IND_T_NAME ON T(OBJECT_NAME);
已解釋。
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
Plan hash value: 517242163
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | CREATE INDEX STATEMENT | | 57915 | 3732K| 75 (2)| 00:00:01 |
| 1 | INDEX BUILD NON UNIQUE| IND_T_NAME | | | | |
| 2 | SORT CREATE INDEX | | 57915 | 3732K| | |
| 3 | INDEX FAST FULL SCAN| IND_T_OWNER_NAME | | | | |
-------------------------------------------------------------------------------------------
Note
-----
- estimated index size: 5242K bytes
已選擇14行。
SQL> SET AUTOT ON
SQL> CREATE INDEX IND_T_NAME ON T(OBJECT_NAME);
索引已建立。
注意,檢視DDL的執行計劃需要使用EXPLAIN PLAN FOR,AUTOTRACE對於DDL是無效的。
4,如何讀懂執行計劃:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (BY INDEX ROWID) OF 'USER_INFO'
3 2 NESTED LOOPS
4 3 TABLE ACCESS (FULL) OF 'USER_NUM_TABLE'
5 3 INDEX (RANGE SCAN) OF 'PK_USER_INFO' (UNIQUE)
請問以上執行計劃語句是如何看的?語句的執行順序是什麼?
讓我們來解釋一下怎麼看吧,左邊的兩列數字,第一列表示這條計劃的編號,第二列是這條計劃的父計劃的編號;如果一條計劃有子計劃,
那麼先要執行其子計劃;在這個例子中:從第一條編號為0的(SELECT STATEMENT ptimizer=CHOOSE)開始,他有個子計劃1(SORT
(AGGREGATE)),然後1有個子計劃2,2有子計劃3, 3 有子計劃4和5,4是3的第一個子計劃,所以先執行4(TABLE ACCESS (FULL)
OF 'USER_NUM_TABLE'),再執行5(INDEX (RANGE SCAN) OF 'PK_USER_INFO' (UNIQUE)),4和5執行完返回到其父計劃3(NESTED
LOOPS),3把4和5取到的rows進行nested loops,結果再返回到2,再到1排序,再到0select.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26892340/viewspace-721500/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Oracle調優之看懂Oracle執行計劃Oracle
- 分析執行計劃優化SQLORACLE的執行計劃(轉)優化SQLOracle
- Oracle優化案例-從執行計劃定位SQL問題(三)Oracle優化SQL
- oracle 固定執行計劃Oracle
- Oracle sql執行計劃OracleSQL
- Oracle優化案例-統計資訊對執行計劃的影響(十三)Oracle優化
- 【執行計劃】Oracle獲取執行計劃的幾種方法Oracle
- 【MySQL】MySQL的執行計劃及索引優化MySql索引優化
- MySQL 5.7 優化不能只看執行計劃MySql優化
- Oracle優化案例-view merge與coe_load_sql_profile固定執行計劃(十五)Oracle優化ViewSQL
- Oracle優化案例-改變那些CBO無能為力的執行計劃(一)Oracle優化
- Oracle-繫結執行計劃Oracle
- 【TUNE_ORACLE】定製化執行計劃SQL參考OracleSQL
- Oracle執行計劃Explain Plan 如何使用OracleAI
- Oracle檢視執行計劃的命令Oracle
- oracle使用outline固定執行計劃事例Oracle
- PostgreSQL執行計劃變化SQL
- MySQL查詢優化之優化器工作流程以及優化的執行計劃生成MySql優化
- mysql調優之——執行計劃explainMySqlAI
- Oracle緊急固定執行計劃之手段Oracle
- Oracle SQL Profile固定執行計劃的方法OracleSQL
- Oracle優化案例-coe_xfr_sql_profile固定執行計劃與刪除profile(二十五)Oracle優化SQL
- MySQL優化從執行計劃開始(explain超詳細)MySql優化AI
- SQL優化案例-從執行計劃定位SQL問題(三)SQL優化
- Calcite執行計劃最佳化
- 執行計劃-1:獲取執行計劃
- 知識篇 | ORACLE 如何執行計劃繫結Oracle
- Oracle如何檢視真實執行計劃(一)Oracle
- Oracle如何手動重新整理執行計劃Oracle
- Oracle 通過註釋改變執行計劃Oracle
- [20191220]格式化執行計劃.txt
- TiDB 查詢優化及調優系列(四)查詢執行計劃的調整及優化原理TiDB優化
- 分析執行計劃優化SQLSQL語句處理的過程(轉)優化SQL
- .Oracle固定執行計劃之SQL PROFILE概要檔案OracleSQL
- 在Oracle中,如何得到真實的執行計劃?Oracle
- SYBASE執行計劃
- MySQL 執行計劃MySql
- MySQL執行計劃MySql
- 【SQL_PLAN】Oracle 透過檢視sql_plan 格式化執行計劃SQLOracle