在 Oracle 數據庫的管理與優化工作中,深入了解 SQL 語句的執行計劃是至關重要的一環。DBMS_XPLAN 包作為 Oracle 提供的強大工具,能夠幫助數據庫管理員(DBAs)和開發人員清晰地查看和分析 SQL 語句的執行計劃,從而實現對數據庫性能的有效優化。本文將全面深入地介紹 DBMS_XPLAN 包的相關知識。
一、DBMS_XPLAN 包概述
DBMS_XPLAN 包是 Oracle 內置的實用工具,主要用于展示 SQL 語句的執行計劃。當我們向 Oracle 數據庫發出一條 SQL 查詢時,數據庫會確定一種最有效的方式來執行該查詢,這個執行方式的具體描述就是執行計劃。執行計劃涵蓋了 Oracle 為檢索或修改所需數據而執行的精確操作,包括表的連接方式、數據的訪問路徑以及索引的使用情況等。
傳統的explain plan語句常用于生成執行計劃,但它僅僅是對執行計劃的預測,并不一定能準確反映 SQL 語句在實際運行時的行為。而 DBMS_XPLAN 包則更具優勢,它不僅可以展示預測的執行計劃,還能根據查詢類型呈現實際運行時的性能表現,為我們深入分析 SQL 語句的執行過程提供了更可靠的依據。
?二、DBMS_XPLAN 包的使用前提
要使用 DBMS_XPLAN 包,需要滿足以下條件:
- 權限要求:用戶需要具備查詢計劃表(plan_table)或v$sql_plan視圖的權限。其中,plan_table是用于存儲explain plan命令輸出結果的臨時表;v$sql_plan視圖則包含了已執行查詢的實際執行計劃。
- SQL 語句的可用性:如果要獲取實時的執行計劃,那么所分析的查詢必須仍然存在于共享 SQL 區域中;如果是進行歷史分析,則需要確保該查詢的執行計劃之前已被捕獲并存儲。
當執行explain plan后,Oracle 會自動向plan_table填充相關內容,此時 DBMS_XPLAN 包就能對這些內容進行格式化處理,使其更易于閱讀和理解。
三、DBMS_XPLAN 包的核心函數
DBMS_XPLAN 包包含多個關鍵函數,每個函數都針對特定的使用場景進行設計,以下是對這些函數的詳細介紹:
3.1 display函數
(一)display函數參數說明
display函數主要用于展示存儲在計劃表(plan_table)中的執行計劃。其調用格式如下:
select * from table(dbms_xplan.display(table_name, statement_id, format, filter_preds));
- table_name:用于指定計劃表的名稱,默認值為plan_table,如果填入null,則表示采用默認的計劃表。?
- statement_id:用于指定 SQL 語句的名稱,默認值為null,在這種情況下,函數將顯示最近插入到計劃表中的執行計劃。?
- format:該參數用于控制輸出內容的格式,常見的取值包括:
- basic:只顯示最基本的信息,簡潔明了。
- typical:顯示常規的執行計劃信息,是較為常用的一種格式。?
- all:展示所有相關信息,內容最為全面。?
- advanced:提供最全的信息,適合對執行計劃進行深入分析的場景。?
- ?filter_preds:用于在查詢計劃表時添加約束條件,例如statement_id = 'test3' 。默認值為null,表示顯示最近插入計劃表的執行計劃,不添加額外約束。
(二)display 示例
首先,使用explain plan for語句生成執行計劃并將其存入plan_table :
explain plan for select * from test1;
然后,通過dbms_xplan.display函數來展示執行計劃:
select * from table(dbms_xplan.display);
這種方式和explain plan展示一樣,這里就不做具體示例展示。
下面補充一個非常實用的功能,就是當一個SQL帶有綁定變量時,explain plan for仍然可以解析。
SQL> explain plan for select object_id,object_name,owner from test1 where rownum<:1;Explained.SQL> select * from table(dbms_xplan.display); PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1430905904----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 91074 | 8538K| 336 (1)| 00:00:05 |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | TABLE ACCESS FULL| TEST1 | 91074 | 8538K| 336 (1)| 00:00:05 |
----------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------1 - filter(ROWNUM<TO_NUMBER(:1))Note
------ dynamic sampling used for this statement (level=2)18 rows selected.
3.2 display_cursor函數
(一)display_cursor函數參數說明
display_cursor函數用于顯示存儲在庫緩存(v$sql_plan視圖 )中的執行計劃,由于它是直接從共享池的library cache內存中直接獲取,所以獲取的執行計劃是真實的,其格式為:
select * from table(dbms_xplan.display_cursor(sql_id, cursor_child_no, format));
- sql_id:指定要返回執行計劃的SQL語句的父游標,默認值為null。當取值為null時,函數將返回當前會話最后被執行的SQL語句的執行計劃。
- cursor_child_no:用于指定父游標下子游標的序號,默認值為0。若將其設定為null,則表示返回所有子游標的執行計劃。
- ?format:與display函數中的format參數類似,用于控制輸出信息的類型。除了前面提到的基本格式外,它還包含一些附加選項,用于定制化輸出行為,這些選項可以通過逗號和空格進行分隔聲明,同時還可以使用+和-符號來包含或排除相應的顯示元素。常見的附加選項如下:
- ? ROWS:顯示被優化器估算的記錄的行號。
- ? ? BYTES:顯示優化器估算的字節數。?
- ? ? COST:顯示優化器計算的成本信息。?
- ? ? PARTITION:顯示分區的分割信息。?
- ? ? PARALLEL:顯示并行執行信息。?
- ? ? PREDICATE:顯示謂語。?
- ? ? PROJECTION:顯示列投影部分,即每一行的哪些列被傳遞給其父列以及這些列的大小。?
- ? ? ALIAS:顯示查詢塊名稱以及對象別名。?
- ? ? REMOTE:顯示分布式查詢信息。?
- ? ? NOTE:顯示注釋。?
- ? ? IOSTATS:顯示游標執行的IO統計信息。?
- ? ? MEMSTATS:為內存密集運算(如散列聯結、排序或一些類型的位圖運算)顯示內存管理統計信息。?
- ? ? PEEKED_BINDS:打印解析時使用的綁定變量
- ? ? ALLSTATS:與IOSTATS MEMSTATS等價。?
- ? ? LAST:顯示最后執行的執行計劃統計信息,默認顯示為ALL類型,并且可以累積。
(二)display_cursor示例
- 展示最近的執行計劃(不帶綁定變量)
dbms_xplan.display_cursor(null, null, 'ALLSTATS LAST')
SQL> set autot off
SQL> select object_id,object_name,owner from test1 where rownum<10;OBJECT_ID OBJECT_NAME OWNER
---------- -------------------- ------------------------------20 ICOL$ SYS46 I_USER1 SYS28 CON$ SYS15 UNDO$ SYS29 C_COBJ# SYS3 I_OBJ# SYS25 PROXY_ROLE_DATA$ SYS41 I_IND1 SYS54 I_CDEF2 SYS9 rows selected.SQL> select * from table(dbms_xplan.display_cursor(null, null, 'ALLSTATS LAST')); PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------
SQL_ID d6tfa5t1a8m7w, child number 0
-------------------------------------
select object_id,object_name,owner from test1 where rownum<10Plan hash value: 1430905904---------------------------------------------
| Id | Operation | Name | E-Rows |
---------------------------------------------
| 0 | SELECT STATEMENT | | |
|* 1 | COUNT STOPKEY | | |
| 2 | TABLE ACCESS FULL| TEST1 | 91074 |
---------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------1 - filter(ROWNUM<10)Note
------ dynamic sampling used for this statement (level=2)- Warning: basic plan statistics not available. These are only collected when:* hint 'gather_plan_statistics' is used for the statement or* parameter 'statistics_level' is set to 'ALL', at session or system level26 rows selected.
這里由于沒有參考統計信息,報一個警告。另外還有其它常用的參數,例如ADVANCED,ALL請讀者自行嘗試。
- 展示最近的執行計劃(帶綁定變量)
-- 1. 創建測試表并插入示例數據
CREATE TABLE employees (employee_id NUMBER PRIMARY KEY,first_name VARCHAR2(50),last_name VARCHAR2(50),department_id NUMBER,salary NUMBER,hire_date DATE
);INSERT INTO employees VALUES (1, 'John', 'Doe', 10, 6000, SYSDATE);
INSERT INTO employees VALUES (2, 'Jane', 'Smith', 20, 7500, SYSDATE-100);
INSERT INTO employees VALUES (3, 'Mike', 'Johnson', 20, 5500, SYSDATE-200);
INSERT INTO employees VALUES (4, 'Sarah', 'Williams', 30, 9000, SYSDATE-150);
COMMIT;-- 2. 創建索引以支持查詢
CREATE INDEX idx_dept_sal ON employees (department_id, salary);-- 3. 執行帶有綁定變量的SQL(使用綁定變量而非硬編碼值)
VARIABLE dept_id NUMBER;
VARIABLE min_salary NUMBER;
EXEC :dept_id := 20;
EXEC :min_salary := 5000;SELECT /*+ MONITOR */ *
FROM employees
WHERE department_id = :dept_id AND salary > :min_salary;-- 4. 立即查看執行計劃(包含綁定變量值)
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ADVANCED ALLSTATS LAST PEEKED_BINDS'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID gd7vts27rnvua, child number 0
-------------------------------------
SELECT /*+ MONITOR */ * FROM employees WHERE department_id = :dept_id
AND salary > :min_salaryPlan hash value: 1445457117--------------------------------------------------------------------------------
| Id | Operation | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
|* 1 | TABLE ACCESS FULL| EMPLOYEES | 2 | 204 | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------1 - SEL$1 / EMPLOYEES@SEL$1Outline Data
-------------/*+BEGIN_OUTLINE_DATAIGNORE_OPTIM_EMBEDDED_HINTSOPTIMIZER_FEATURES_ENABLE('11.2.0.4')DB_VERSION('11.2.0.4')ALL_ROWSOUTLINE_LEAF(@"SEL$1")FULL(@"SEL$1" "EMPLOYEES"@"SEL$1")END_OUTLINE_DATA*/Peeked Binds (identified by position):
--------------------------------------1 - (NUMBER): 202 - (NUMBER): 5000Predicate Information (identified by operation id):
---------------------------------------------------1 - filter(("DEPARTMENT_ID"=:DEPT_ID AND "SALARY">:MIN_SALARY))Column Projection Information (identified by operation id):
-----------------------------------------------------------1 - "EMPLOYEES"."EMPLOYEE_ID"[NUMBER,22],"EMPLOYEES"."FIRST_NAME"[VARCHAR2,50],"EMPLOYEES"."LAST_NAME"[VARCHAR2,50], "DEPARTMENT_ID"[NUMBER,22],"SALARY"[NUMBER,22], "EMPLOYEES"."HIRE_DATE"[DATE,7]Note
------ dynamic sampling used for this statement (level=2)- Warning: basic plan statistics not available. These are only collected when
:* hint 'gather_plan_statistics' is used for the statement or* parameter 'statistics_level' is set to 'ALL', at session or system leve
l59 rows selected.
- 通過SQLID和游標ID獲取執行計劃
通過執行select * from table(dbms_xplan.display_cursor('sql_id/hash_value', child_cursor_number, 'advanced'))查看指定 SQL 的執行計劃 。
- 第一個參數為 SQL ID 或 SQL HASH VALUE?
- 第二個是 Child Cursor Number?
- 第三個常用advanced以呈現最詳細執行計劃。
--查看SQLID及游標號
select sql_id,child_number from v$sql where sql_text like 'select object_id,object_name,owner from test1 where%';SQL_ID CHILD_NUMBER
------------- ------------
d6tfa5t1a8m7w 0--查看執行計劃
SQL>
set pages 1000
select * from table(dbms_xplan.display_cursor('d6tfa5t1a8m7w',0,'advanced'));PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID d6tfa5t1a8m7w, child number 0
-------------------------------------
select object_id,object_name,owner from test1 where rownum<10Plan hash value: 1430905904----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
|* 1 | COUNT STOPKEY | | | | | |
| 2 | TABLE ACCESS FULL| TEST1 | 91074 | 8538K| 2 (0)| 00:00:01 |
----------------------------------------------------------------------------Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------1 - SEL$12 - SEL$1 / TEST1@SEL$1Outline Data
-------------/*+BEGIN_OUTLINE_DATAIGNORE_OPTIM_EMBEDDED_HINTSOPTIMIZER_FEATURES_ENABLE('11.2.0.4')DB_VERSION('11.2.0.4')ALL_ROWSOUTLINE_LEAF(@"SEL$1")FULL(@"SEL$1" "TEST1"@"SEL$1")END_OUTLINE_DATA*/Predicate Information (identified by operation id):
---------------------------------------------------1 - filter(ROWNUM<10)Column Projection Information (identified by operation id):
-----------------------------------------------------------1 - "OWNER"[VARCHAR2,30], "OBJECT_NAME"[VARCHAR2,128],"OBJECT_ID"[NUMBER,22]2 - "OWNER"[VARCHAR2,30], "OBJECT_NAME"[VARCHAR2,128],"OBJECT_ID"[NUMBER,22]Note
------ dynamic sampling used for this statement (level=2)51 rows selected.
注意:當目標 SQL 執行計劃所在的 Child Cursor 未因空間不足等原因被從共享池(Shared Pool)中置換出去(age out )時才能查到執行計劃。
3.3 display_awr函數
當 SQL 的執行計劃被 age out 出 Shared Pool 后,若該執行計劃此前被 Oracle 采集并存儲到 AWR(自動工作量存儲庫,AWR Repository )中,就可以使用該方法查看該 SQL 的所有歷史執行計劃 。AWR 定期收集、處理和存儲數據庫性能統計信息以及執行計劃等相關數據,即使執行計劃不在共享池,只要已被采集到 AWR 中,就能通過特定方法來查看歷史執行計劃,這為分析 SQL 在不同時間、不同條件下的執行情況提供了途徑 。
(一)display_awr函數參數說明
display_awr函數能夠從自動工作量存儲庫(AWR)中存儲的歷史數據里獲取并顯示執行計劃。這在分析過去某個時段內 SQL 語句的執行情況時非常有用,有助于排查歷史性能問題。其語法格式為:
select * from table(dbms_xplan.display_awr(sql_id, plan_hash_value, dbid, format));
其中,sql_id是 SQL 語句的標識;plan_hash_value是執行計劃的哈希值;dbid是數據庫的唯一標識;format同樣用于控制輸出格式。
(二)display_awr 示例
- 查看當前共享池中的執行計劃
SQL> col SQL_TEXT for a40
select sql_text, sql_id, version_count,executions from v$sqlarea where sql_text like 'SELECT /*+ MONITOR */ * FROM employees WHERE department_id = :dept_id%'; SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS
---------------------------------------- ------------- ------------- ----------
SELECT /*+ MONITOR */ * FROM employees W gd7vts27rnvua 1 1
HERE department_id = :dept_id AND sala
ry > :min_salary
- 采集AWR
exec dbms_workload_repository.create_snapshot();
- 清空共享池
alter system flush shared_pool;
- 確認執行計劃被置換出共享池
SQL> select sql_text, sql_id, version_count,executions from v$sqlarea where sql_text like 'SELECT /*+ MONITOR */ * FROM employees WHERE department_id = :dept_id%'; no rows selectedselect * from table(dbms_xplan.display_cursor('gd7vts27rnvua',0,'advanced'));PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID: gd7vts27rnvua, child number: 0 cannot be found
- 確認執行計劃被置換出共享池
SQL> select * from table(dbms_xplan.display_awr('gd7vts27rnvua'));PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID gd7vts27rnvua
--------------------
SELECT /*+ MONITOR */ * FROM employees WHERE department_id = :dept_id
AND salary > :min_salaryPlan hash value: 1445457117-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | TABLE ACCESS FULL| EMPLOYEES | 2 | 204 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------Note
------ dynamic sampling used for this statement (level=2)18 rows selected.
與DBMS_XPLAN.DISPLAY_CURSOR相比,DBMS_XPLAN.DISPLAY_AWR顯示的執行計劃存在不足,無法呈現執行步驟對應的謂詞條件(包括驅動和過濾查詢條件 )。這是由于Oracle將執行計劃采樣數據從V$SQL_PLAN遷移到AWR Repository基表WRH$_SQL_PLAN時,未保留記錄謂詞條件的ACCESS_PREDICATES和FILTER_PREDICATES列的值,導致DBMS_XPLAN.DISPLAY_AWR無相關條件可展示,而謂詞條件對理解執行計劃尤其是復雜計劃至關重要。
(四)display_sts函數
display_sts函數主要用于檢索存儲在 SQL 調試集(STS)中特定 SQL 語句的執行計劃。其語法如下:
select * from table(dbms_xplan.display_sts(sqlset_name, sqlset_owner, sql_id, format));
這里,sqlset_name是 SQL 調試集的名稱;sqlset_owner是 SQL 調試集的所有者;sql_id是需要查詢執行計劃的 SQL 語句標識;format用于控制輸出信息。
這個使用場景不多,不做過多介紹。
五、DBMS_XPLAN 包的使用總結
DBMS_XPLAN 包在 Oracle 數據庫中是查看 SQL 執行計劃的得力工具,涵蓋了從緩存、AWR、SQL 調試集等多來源的計劃展示。通過掌握其各函數的功能、使用方法及適用場景,并留意權限與參數設置等要點,能助力數據庫管理員和開發人員精準剖析 SQL 執行情況,高效開展性能優化工作。