sql執行計划:把SQL語句拆分為每個的操作步驟組合,按照一定的順序執行得出結果,查看並看懂執行計划是調優的關鍵步驟
查看執行計划的方法
- DBMS_XPLAN包
- sql*plus AUTO trace
- V$SQL_PLAN、DBA_HIST_SQL_PLAN
- ?/rdbms/admin/awrsqrpt.sql
- 工具類:toad、pl/SQL DEV
- 跟蹤dump:10046,10053
大多數人比較喜歡用工具直接看,以下來說明這些方式的不同用處
一、DBMS_XPLAN包
10g以后可以查看AWR中的語句執行計划,也可以查看當前內存中游標的執行計划。
主要有以下五個方法:
-
DISPLAY
- 格式化並顯示plan table中內容,類似工具的F5(EXPLAIN PLAN FOR …) -
DISPLAY_AWR
-格式和顯示存儲在AWR中的SQL語句的執行計划。數據來源: DBA_HIST_SQL_PLAN,DBA_HIST_SQLTEXT -
DISPLAY_CURSOR
-格式和顯示任何加載游標執行計划的內容。數據來源:V$SQL_PLAN和V$SQL_PLAN_STATISTICS_ALL -
DISPLAY_SQL_PLAN_BASELINE
- 顯示一個或多個執行計划的SQL語句通過SQL handle 標識 。數據來源:DBA_SQL_PLAN_BASELINES -
DISPLAY_SQLSET
- 格式和顯示存儲在sql調優集中的執行計划內容。數據來源:ALL_SQLSET_STATEMENTS、ALL_SQLSET_PLANS
最常用的DISPLAY_AWR和DISPLAY_CURSOR,來闡述具體的調用方式,顯示的內容
(一)、DISPLAY_CURSOR
顯示當前shared pool->library cache中的執行計划
DBMS_XPLAN.DISPLAY_CURSOR( sql_id IN VARCHAR2 DEFAULT NULL, cursor_child_no IN NUMBER DEFAULT 0, format IN VARCHAR2 DEFAULT 'TYPICAL');
參數 | 說明(常用說明) |
sql_id | SQL的唯一標識,取SELECT SQL_ID FROM V$SQL,為null的情況下,取上一條語句的執行計划 |
cursor_child_no | 子游標的id號,為null,取出全部子游標的執行計划 |
format | 輸出格式化 默認TYPICAL ADVANCED +PEEKED_BINDS ALLSTATS |
例子查看
#默認格式輸出select * from table(dbms_xplan.display_cursor('bjqjt2dfvya84',null))
SQL_ID bjqjt2dfvya84, child number 0
-------------------------------------
select * from emp where empno=7521
Plan hash value: 2949544139
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 1 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 38 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"=7521)
#格式化為ADVANCED +PEEKED_BINDS
select * from table(dbms_xplan.display_cursor('bjqjt2dfvya84',null,'ADVANCED +PEEKED_BINDS'))
SQL_ID bjqjt2dfvya84, child number 0
-------------------------------------
select * from emp where empno=7521
Plan hash value: 2949544139
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 1 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 38 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| |
--------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1 / EMP@SEL$1
2 - SEL$1 / EMP@SEL$1
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('11.2.0.3')
DB_VERSION('11.2.0.3')
OPT_PARAM('optimizer_dynamic_sampling' 0)
ALL_ROWS
OUTLINE_LEAF(@"SEL$1")
INDEX_RS_ASC(@"SEL$1" "EMP"@"SEL$1" ("EMP"."EMPNO"))
END_OUTLINE_DATA
*/
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"=7521)
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - "EMPNO"[NUMBER,22], "EMP"."ENAME"[VARCHAR2,10],
"EMP"."JOB"[VARCHAR2,9], "EMP"."MGR"[NUMBER,22], "EMP"."HIREDATE"[DATE,7],
"EMP"."SAL"[NUMBER,22], "EMP"."COMM"[NUMBER,22], "EMP"."DEPTNO"[NUMBER,22]
2 - "EMP".ROWID[ROWID,10], "EMPNO"[NUMBER,22]
#格式化ALLSTATS
兩種處理方式: * hint 'gather_plan_statistics' is used for the statement or
* parameter 'statistics_level' is set to 'ALL', at session or system level
select /*+gather_plan_statistics*/ * from emp where empno=7521
select * from table(dbms_xplan.display_cursor('dvj95t2z1gh2a',null,'ALLSTATS'))
SQL_ID dvj95t2z1gh2a, child number 0
-------------------------------------
select /*+gather_plan_statistics*/ * from emp where empno=7521
Plan hash value: 2949544139
------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 2 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 1 | 1 |00:00:00.01 | 2 |
|* 2 | INDEX UNIQUE SCAN | PK_EMP | 1 | 1 | 1 |00:00:00.01 | 1 |
------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"=7521)
A-ROW是實際的行數,E-ROW是優化器評估的
(二)、DISPLAY_AWR
顯示AWR中的SQL的執行計划,對分析歷史SQL慢的相當有幫組
DBMS_XPLAN.DISPLAY_AWR( sql_id IN VARCHAR2, plan_hash_value IN NUMBER DEFAULT NULL, db_id IN NUMBER DEFAULT NULL, format IN VARCHAR2 DEFAULT TYPICAL);
參數 | 常用說明 |
SQL_ID | SQL的唯一標識,取SELECT SQL_ID FROM DBA_HIST_SQLTEXT |
PLAN_HASH_VALUE | 指定SQL語句的PLAN_HASH_VALUE,忽略取全部的SQL_ID下的執行計划 |
DB_ID | 默認取V$DATABASE.DATABASE_ID |
FORMAT | 輸出格式化 默認TYPICAL ADVANCED +PEEKED_BINDS |
例子查看
#默認輸出的格式 select * from table(dbms_xplan.display_awr('bjqjt2dfvya84')); SQL_ID bjqjt2dfvya84 -------------------- select * from emp where empno=7521 Plan hash value: 2949544139 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 1 (100)| | | 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 38 | 1 (0)| 00:00:01 | | 2 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| | -------------------------------------------------------------------------------------- #通過格式化ADVANCED +PEEKED_BINDS select * from table(dbms_xplan.display_awr('bjqjt2dfvya84',FORMAT=>'ADVANCED +PEEKED_BINDS')); SQL_ID bjqjt2dfvya84 -------------------- select * from emp where empno=7521 Plan hash value: 2949544139 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 1 (100)| | | 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 38 | 1 (0)| 00:00:01 | | 2 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| | -------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 / EMP@SEL$1 2 - SEL$1 / EMP@SEL$1 Outline Data ------------- /*+ BEGIN_OUTLINE_DATA IGNORE_OPTIM_EMBEDDED_HINTS OPTIMIZER_FEATURES_ENABLE('11.2.0.3') DB_VERSION('11.2.0.3') OPT_PARAM('optimizer_dynamic_sampling' 0) ALL_ROWS OUTLINE_LEAF(@"SEL$1") INDEX_RS_ASC(@"SEL$1" "EMP"@"SEL$1" ("EMP"."EMPNO")) END_OUTLINE_DATA */
二、sqlplus autotrace
scott@GULL> set autotrace
用法: SET AUTOT[RACE] {OFF | ON | TRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]]
可以體現執行語句的執行計划和統計信息
scott@GULL> SET autotrace trace scott@GULL> select * from emp where empno=7521; 執行計划 ---------------------------------------------------------- Plan hash value: 2949544139 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 38 | 1 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 38 | 1 (0)| 00:00:01 | |* 2 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 (0)| 00:00:01 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("EMPNO"=7521) 統計信息 ---------------------------------------------------------- 0 recursive calls 0 db block gets 2 consistent gets 0 physical reads 0 redo size 902 bytes sent via SQL*Net to client 508 bytes received via SQL*Net from client 1 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1 rows processed scott@GULL>
三、V$SQL_PLAN
直接取數據字典的源數據
scott@GULL> col id format 99; scott@GULL> col parent_id format 99999; scott@GULL> col operation format a25; scott@GULL> col options format a20; scott@GULL> select id,parent_id,operation,options from V$SQL_PLAN where sql_id='bjqjt2dfvya84'; ID PARENT_ID OPERATION OPTIONS --- --------- ------------------------- -------------------- 0 SELECT STATEMENT 1 0 TABLE ACCESS BY INDEX ROWID 2 1 INDEX UNIQUE SCAN
四、?/rdbms/admin/awrsqrpt.sql
查看AWR中執行計划,調用這個腳本后,相關的直觀展現
scott@GULL> @?/rdbms/admin/awrsqrpt.sql Current Instance ~~~~~~~~~~~~~~~~ DB Id DB Name Inst Num Instance ----------- ------------ -------- ------------ 3239200222 GULL 1 gullstby Specify the Report Type ~~~~~~~~~~~~~~~~~~~~~~~ Would you like an HTML report, or a plain text report? Enter 'html' for an HTML report, or 'text' for plain text Defaults to 'html' 輸入 report_type 的值: html Type Specified: html Instances in this Workload Repository schema ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DB Id Inst Num DB Name Instance Host ------------ -------- ------------ ------------ ------------ * 3239200222 1 GULL gullstby gull02 Using 3239200222 for database Id Using 1 for instance number Specify the number of days of snapshots to choose from ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Entering the number of days (n) will result in the most recent (n) days of snapshots being listed. Pressing <return> without specifying a number lists all completed snapshots. 輸入 num_days 的值: 1 Listing the last day's Completed Snapshots Snap Instance DB Name Snap Id Snap Started Level ------------ ------------ --------- ------------------ ----- gullstby GULL 368 01 6月 2016 10:08 1 369 01 6月 2016 10:12 1 Specify the Begin and End Snapshot Ids ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 輸入 begin_snap 的值: 368 Begin Snapshot Id specified: 368 輸入 end_snap 的值: 369 End Snapshot Id specified: 369 Specify the SQL Id ~~~~~~~~~~~~~~~~~~ 輸入 sql_id 的值: bjqjt2dfvya84 SQL ID specified: bjqjt2dfvya84 Specify the Report Name ~~~~~~~~~~~~~~~~~~~~~~~ The default report file name is awrsqlrpt_1_368_369.html. To use this name, press <return> to continue, otherwise enter an alternative. 輸入 report_name 的值: /home/oracle/0601.html
五、工具類:toad(ctrl+e)、pl/SQL DEV(f5)
工具類查看執行計划,非常快捷、簡單、能清楚知道每部步驟的優先級,但是他們實際調用的是EXPLAIN PLAN for,寫入plan_TABLE,是優化器的預評估,不是正在SQL執行時的執行計划。簡單分析是有用的,但是在你的應用程序中SQL很慢,常用的SQL用toad等很快,此時就不要在用工具快捷方式去查看執行計划,要去分析正在執行的執行計划,采用以上的內容方式。
toad(ctrl+e)
五、10046
10046這個事件是查看SQL具體的執行步驟,等待的是什么事件,實際內部調用的是哪些SQL。SQL語句執行很慢時,可以查看具體等待的是什么,導致執行這么慢。還有對我們了解create 、truncate具體在執行哪些語句有幫組。
SQL> conn /as sysdba 已連接。 SQL> ALTER SESSION SET EVENTS '10046 trace name context forever, level 28'; 會話已更改。 SQL> select * from scott.emp where empno=7521; SQL> select c.value || '/' || d.instance_name || '_ora_' || 2 a.spid || '.trc' || 3 case when e.value is not null then '_'||e.value end trace 4 from v$process a, v$session b, v$parameter c, v$instance d, v$parameter e 5 where a.addr = b.paddr 6 and b.sid = userenv('sid') 7 and c.name = 'user_dump_dest' 8 and e.name = 'tracefile_identifier'; TRACE -------------------------------------------------------------------------------- /u01/app/oracle/diag/rdbms/orclstby/orcl/trace/orcl_ora_3288.trc 查看日志文件的內容 .... PARSING IN CURSOR #139774981787448 len=41 dep=0 uid=0 oct=3 lid=0 tim=1464851500943287 hv=3602254372 ad='d4180e00' sqlid='89mgdagbbc2j4' select * from scott.emp where empno=7521 END OF STMT PARSE #139774981787448:c=60990,e=224928,p=20,cr=444,cu=0,mis=1,r=0,dep=0,og=1,plh=2949544139,tim=1464851500943287 EXEC #139774981787448:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=2949544139,tim=1464851500943287 WAIT #139774981787448: nam='SQL*Net message to client' ela= 1 driver id=1650815232 #bytes=1 p3=0 obj#=5473 tim=1464851500943295 WAIT #139774981787448: nam='Disk file operations I/O' ela= 29 FileOperation=2 fileno=4 filetype=2 obj#=75336 tim=1464851500943586 WAIT #139774981787448: nam='db file sequential read' ela= 11120 file#=4 block#=155 blocks=1 obj#=75336 tim=1464851500954730 WAIT #139774981787448: nam='db file sequential read' ela= 428 file#=4 block#=151 blocks=1 obj#=75335 tim=1464851500955277 FETCH #139774981787448:c=0,e=12010,p=2,cr=2,cu=0,mis=0,r=1,dep=0,og=1,plh=2949544139,tim=1464851500955332 STAT #139774981787448 id=1 cnt=1 pid=0 pos=1 obj=75335 op='TABLE ACCESS BY INDEX ROWID EMP (cr=2 pr=2 pw=0 time=11994 us cost=1 size=38 card=1)' STAT #139774981787448 id=2 cnt=1 pid=1 pos=1 obj=75336 op='INDEX UNIQUE SCAN PK_EMP (cr=1 pr=1 pw=0 time=11487 us cost=0 size=0 card=1)' WAIT #139774981787448: nam='SQL*Net message from client' ela= 297 driver id=1650815232 #bytes=1 p3=0 obj#=75335 tim=1464851500955736 FETCH #139774981787448:c=0,e=2,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,plh=2949544139,tim=1464851500955773 WAIT #139774981787448: nam='SQL*Net message to client' ela= 1 driver id=1650815232 #bytes=1 p3=0 obj#=75335 tim=1464851500955791 采用tkprof格式化10046,看起來更加的清晰 [oracle@gull2 ~]$ tkprof /u01/app/oracle/diag/rdbms/orclstby/orcl/trace/orcl_ora_3288.trc /home/oracle/3288.trc 查看3288.trc SQL ID: 89mgdagbbc2j4 Plan Hash: 2949544139 select *afrom scott.emp where empno=7521 call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.06 0.22 0 444 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 2 0.00 0.01 2 2 0 1 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 4 0.06 0.23 2 446 0 1 Misses in library cache during parse: 1 Optimizer mode: ALL_ROWS Parsing user id: SYS Number of plan statistics captured: 1 Rows (1st) Rows (avg) Rows (max) Row Source Operation ---------- ---------- ---------- --------------------------------------------------- 1 1 1 TABLE ACCESS BY INDEX ROWID EMP (cr=2 pr=2 pw=0 time=11994 us cost=1 size=38 card=1) 1 1 1 INDEX UNIQUE SCAN PK_EMP (cr=1 pr=1 pw=0 time=11487 us cost=0 size=0 card=1)(object id 75336) Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------------------- Waited ---------- ------------ SQL*Net break/reset to client 2 0.00 0.00 SQL*Net message to client 3 0.00 0.00 SQL*Net message from client 2 11.43 11.43 Disk file operations I/O 1 0.00 0.00 db file sequential read 2 0.01 0.01
六、10053
10053這個事件是查看為什么SQL語句評估出發的執行計划是這樣的,優化器如何評估出來這個執行計划的,記錄優化器的計算值
SQL> conn /as sysdba 已連接。 SQL> oradebug setmypid; 已處理的語句 SQL> oradebug event 10053 trace name context forever ,level 1; 已處理的語句 SQL> select * from scott.emp where empno=7521; EMPNO ENAME JOB MGR ---------- ------------------------------ --------------------------- ---------- HIREDATE SAL COMM DEPTNO -------------- ---------- ---------- ---------- 7521 WARD SALESMAN 7698 22-2月 -81 1250 500 30 SQL> oradebug tracefile_name /u01/app/oracle/diag/rdbms/orclstby/orcl/trace/orcl_ora_9109.trc ....... Starting SQL statement dump user_id=0 user_name=SYS module=sqlplus@gull2 (TNS V1-V3) action= sql_id=b250dw0hyz0rs plan_hash_value=-1345423157 problem_type=3 ----- Current SQL Statement for this session (sql_id=b250dw0hyz0rs) ----- select * from scott.emp where empno=7521 sql_text_length=49 sql= select * from scott.emp where empno=7521 ----- Explain Plan Dump ----- ----- Plan Table ----- ============ Plan Table ============ -----------------------------------------------+-----------------------------------+ | Id | Operation | Name | Rows | Bytes | Cost | Time | -----------------------------------------------+-----------------------------------+ | 0 | SELECT STATEMENT | | | | 1 | | | 1 | TABLE ACCESS BY INDEX ROWID | EMP | 1 | 38 | 1 | 00:00:01 | | 2 | INDEX UNIQUE SCAN | PK_EMP | 1 | | 0 | | -----------------------------------------------+-----------------------------------+ Predicate Information: ---------------------- 2 - access("EMPNO"=7521) Content of other_xml column =========================== db_version : 11.2.0.3 parse_schema : SYS plan_hash : 2949544139 plan_hash_2 : 1767686164 Outline Data: /*+ BEGIN_OUTLINE_DATA IGNORE_OPTIM_EMBEDDED_HINTS OPTIMIZER_FEATURES_ENABLE('11.2.0.3') DB_VERSION('11.2.0.3') ALL_ROWS OUTLINE_LEAF(@"SEL$1") INDEX_RS_ASC(@"SEL$1" "EMP"@"SEL$1" ("EMP"."EMPNO")) END_OUTLINE_DATA */
總結
1、查看真實的執行計划,使用DBMS_XPLAN.DISPLAY_CUROR這個過程,可以清晰的展示SHARED_POOL-》libarary中的執行計划,不需要你重新去運行SQL語句,根據不同的格式輸出你需要的內容,可以查看出統計信息是否陳舊、謂詞中的字段類型是否有隱式轉化(導致索引不能使用)等
2、DBMS_XPLAN.DISPLAY_AWR,查看AWR中的執行計划,是否存在多個執行計划,代價比較高-》消耗性能厲害的,更加直觀的可以調用?/rdbms/admin/awrsqrpt.sql
3、sql*plus autotrace 需要重新去運行一遍SQL語句,查看現在運行的這個語句的執行計划,無法查看到,你程序中運行的那條語句的執行計划
4、工具調用(如toad 、PL/SQL DEV),實際采用的EXPLAIN PLAN FOR... 保存到plan_TABLE,是優化器的預評估。
5、10046的事件使用的范圍在調試一個語句執行很慢,想清楚具體等待的是什么,慢在哪個階段,還可以查看一些DDL的語句,內部語句的構造的方式,但查看執行計划,10046不是特別的方便,需要重新執行SQL語句,到服務器端拿日志文件
6、10053的事件可以用來分析 SQL語句為什么會做這個執行計划(如沒有走索引,而是走了全表掃描)