2019独角兽企业重金招聘Python工程师标准>>>
---王鹏冲/20171212
一、oracle如何查看SQL执行计划:
方法1:
通过dbms_xplan.display_cursor来查看sql当前在内存中实际的执行计划(这个包实际就是从v$sql_plan里面取得的执行计划,做了封装和格式化):
display_cursor语法:
SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR('&sql_id'));
SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR('&sql_id',&child_number));
select * from table(dbms_xplan.display_cursor('&sql_id','&child_number','options'));
display_cursor的一些比较强大的options:
a. 'All'
b. 'advanced'
c. 'peeked_binds'
d. 'outline'
e. 'allstats last'
例如:
SQL> select * from table(dbms_xplan.display_cursor('c9cxqvr3q4tjd'));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID c9cxqvr3q4tjd, child number 0
-------------------------------------
select count(0) from cat_product cp,cat_drug cd where cp.medical_id=cd.id
Plan hash value: 2559475106
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | | 750 (100)| |
| 1 | SORT AGGREGATE | | 1 | 50 | | | |
|* 2 | HASH JOIN | | 118K| 5804K| 4096K| 750 (1)| 00:00:11 |
| 3 | INDEX FAST FULL SCAN| PK_CAT_DRUG | 112K| 2758K| | 186 (1)| 00:00:03 |
| 4 | INDEX FAST FULL SCAN| TU_CAT_PRODUCT_MED_CHECK | 118K| 2902K| | 212 (1)| 00:00:03 |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("CP"."MEDICAL_ID"="CD"."ID")
方法2:
查v$sql_plan里面的执行计划
方法3:
查dba_hist_sqlplan里面历史的执行计划。
方法4:
查看sql历史的执行计划(如果有改变,会有多个执行计划查出来):
SELECT * FROM table(DBMS_XPLAN.DISPLAY_AWR('&sql_id',null,null,'ALL'));
方法5:
如果内存中找不到这个sql,那么可以通过plsql developer工具的查看执行计划的选项功能来查看,但是这个执行计划只是工具根据统计信息预估出来的,可能与实际的执行计划存在偏差的可能。
方法6:
如果内存中找不到这个sql,也可以通过如下这种方式来获取执行计划,但是这个执行计划只是工具根据统计信息预估出来的,可能与实际的执行计划存在偏差的可能。
EXPLAIN PLAN FOR ......select SQL_Statement......;
select * from table(dbms_xplan.display);
二,如何知道sql的执行效率指标:
方法1:
查询v$sql里面的相关指标(适用于sql运行后,查看sql在内存中的实际效率),例如:
select
a.sql_id, a.sql_text,
a.PLAN_HASH_VALUE,
round(a.BUFFER_GETS/a.EXECUTIONS) bg_per_exec,
round(a.CPU_TIME/1000/a.EXECUTIONS) cpu_per_exec,
round(a.ELAPSED_TIME/1000/a.EXECUTIONS) time_per_exec,
round(a.ROWS_PROCESSED/a.EXECUTIONS) rows_per_exec,
a.EXECUTIONS,
a.BUFFER_GETS,
a.DISK_READS,
a.CPU_TIME,
a.ELAPSED_TIME,
a.ROWS_PROCESSED
from v$sql a
where hash_value=377282797
and cpu_time<>0
and buffer_gets<>0
and rows_processed<>0
order by sql_text
/
方法2:
---sql历史上逻辑读、物理读、执行时间的变化 (毫秒)
select b.begin_interval_time, a.sql_id,a.plan_hash_value,a.executions_delta,
round((a.buffer_gets_delta) /decode(nvl(a.executions_delta, 0),0,1, a.executions_delta),3) bg_per_exec,
round((a.disk_reads_delta) /decode(nvl(a.executions_delta, 0),0,1, a.executions_delta),3) diskr_per_exec,
round((a.cpu_time_delta/1000) /decode(nvl(a.executions_delta, 0),0,1, a.executions_delta),3) ctime_ms_per_exec,
round((a.elapsed_time_delta/1000) /decode(nvl(a.executions_delta, 0),0,1, a.executions_delta),3) etime_ms_per_exec,
round((a.APWAIT_DELTA/1000) /decode(nvl(a.executions_delta, 0),0,1, a.executions_delta),3) APWAIT_DELTA_ms_per_exec,
round((a.CCWAIT_DELTA/1000) /decode(nvl(a.executions_delta, 0),0,1, a.executions_delta),3) CCWAIT_DELTA_ms_per_exec,
round((a.rows_processed_delta) /decode(nvl(a.executions_delta, 0),0,1, a.executions_delta),3) row_process_per_exec
from dba_hist_sqlstat a, dba_hist_snapshot b
where a.sql_id = '8hf3kwj1z14ch'
and a.instance_number=b.instance_number
and a.instance_number=2
and b.begin_interval_time> to_date('2017-10-05 09:00:00','yyyy-mm-dd hh24:mi:ss')
and b.begin_interval_time
;
方法3:
在oracle sqlplus客户端(plsql developer工具不支持),通过set autotrace来查看(适用于在测试库反复调试对比sql执行效率),例如:
SQL> set autotrace traceonly;
SQL> select * from t2;
已选择402344行。
执行计划
----------------------------------------------------------
Plan hash value: 1513984157
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 402K| 33M| 1240 (3)| 00:00:15 |
| 1 | TABLE ACCESS FULL| T2 | 402K| 33M| 1240 (3)| 00:00:15 |
--------------------------------------------------------------------------
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
911 bytes sent via SQL*Net to client
190 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
402344 rows processed
/******set autotrace 详细选项******/
在SQL/PLUS的窗口运行以下命令 :
set time on; (说明:打开时间显示)
set timing on; (说明:打开sql执行时间显示)
set autotrace on; (说明:打开自动分析统计,并显示SQL语句的运行结果)
set autotrace off;
用法: SET AUTOT[RACE] {OFF | ON | TRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]]
举例:
SET AUTOT[RACE] OFF 停止AutoTrace
SET AUTOT[RACE] ON 开启AutoTrace,显示AUTOTRACE信息和SQL执行结果
SET AUTOT[RACE] TRACEONLY 开启AutoTrace,仅显示AUTOTRACE信息,不返回sql运行结果(在有大量行返回时比较有用,避免返回结果过多干扰)
SET AUTOT[RACE] ON EXPLAIN 开启AutoTrace,仅显示AUTOTRACE的EXPLAIN信息
SET AUTOT[RACE] ON STATISTICS开启AutoTrace,仅显示AUTOTRACE的STATISTICS信息
结果解释
consistent gets 逻辑读-一致性读
physical reads 物理读——执行SQL的过程中,从硬盘上读取的数据块个数
redo size 重做数——执行SQL的过程中,产生的重做日志的大小
bytes set via sql*net to client 通过sql*net发送给客户端的字节数
bytes received via sql*net from client 通过sql*net接受客户端的字节数
sorts(memory) 在内存中发生的排序
sorts(disk) 不能在内存中发生的排序,需要硬盘来协助
rows processed 结果的记录数
/******set autotrace 详细选项******/
三、其它方法:
1,设置event
通过设置10046、10053 event trace
2,设置sql_trace
exec dbms_monitor.session_trace_enable;
exec dbms_monitor.database_trace_enable();
exec dbms_session.set_sql_trace(true);
exec dbms_system.set_sql_trace_in_session(sid,serial#,true);
exec dbms_monitor.session_trace_disable;
exec dbms_monitor.database_trace_disable();
exec dbms_session.set_sql_trace(false);
exec dbms_system.set_sql_trace_in_session(sid,serial#,false);