一、plsql developer工具F5
在sqldeveloper中选中sql按F5即可查看执行计划
二、explain plan for
在sql plus中执行 explain plan for SQL语句,然后执行sql获取执行计划
Select * from table(DBMS_XPLAN.display('PLAN_TABLE'));
这种方式和直接按F5 结果是一样的。
优点:不用执行sql即可获取执行计划,方便
缺点:没办法看执行了多少次逻辑读,多少次物理读,表访问了多少次,处理了多少行。
三、set autotrace on
在sql plus中执行命令,set autotrace on 开启trace,然后执行sql,完成之后会出结果
注:
Set autotrace on:得到执行计划,输出运行结果
Set autotrace traceonly :得到执行计划,不输出运行结果
Set autotrace traceonly explain :得到执行计划,不输出运行结果和统计信息部分,仅展现执行计划部分
Set autotrace traceonly statistics :不输出运行结果和执行计划部分,仅展现统计信息部分
该命令不能在plsql developer中使用,得在 sql*plus中使用
优点:可以看到执行过程的统计信息(执行了多少次逻辑读,多少次物理读等信息)
可以看到执行了处理了多少行
缺点:必须等sql运行结束
没办法看到表被访问了多少次
四、statistics_level=all
1.执行语句,设置statistics_level
alter session set statistics_level=all;
2.运行sql,查找对应的SQL_ID
运行sql时可以加一些注释,方便查找
select * from v$sqlarea where sql_text like '%sunlingchao%';
3.执行以下SQL获取执行计划
select * from table(dbms_xplan.display_cursor('&sql_id',null,'allstats last'));
或者
1.在执行SQL的时候加上hint
/*+ gather_plan_statistics */
2.执行上面第3步获取执行计划
关键字解读:
Starts:该sql执行的次数。
E-Rows:执行计划预估的行数。
A-Rows:实际返回的行数。A-Rows跟E-Rows做比较,可以确定哪一步执行计划出问题。
A-Time:每一步实际执行的时间(HH:MM:SS.FF),根据这一行可以知道该sql耗时在了哪个地方。
Buffers:每一步实际执行的逻辑读或一致性读。
Reads:物理读。
OMem:当前操作完成所有内存工作区(Work Aera)操作所总共使用私有内存(PGA)中工作区的大小,这个数据是由优化器统计数据以及前一次执行的性能数据估算得出的
1Mem:当工作区大小无法满足操作所需的大小时,需要将部分数据写入临时磁盘空间中(如果仅需要写入一次就可以完成操作,就称一次通过,One-Pass;否则为多次通过,Multi_Pass).该列数据为语句最后一次执行中,单次写磁盘所需要的内存大小,这个由优化器统计数据以及前一次执行的性能数据估算得出的
User-Mem:语句最后一次执行中,当前操作所使用的内存工作区大小,括号里面为(发生磁盘交换的次数,1次即为One-Pass,大于1次则为Multi_Pass,如果没有使用磁盘,则显示OPTIMAL)
OMem、1Mem为执行所需的内存评估值,0Mem为最优执行模式所需内存的评估值,1Mem为one-pass模式所需内存的评估值。0/1/M 为最优/one-pass/multipass执行的次数。Used-Mem耗的内存。
优点:可以清晰看出来表被访问多少次;有详细的E-Rows和A-Rows中得到预测的行数和真实的行数;从Buffers中看真实的逻辑读
缺点:必须等到sql执行结束;必须将查询结果输出,遇到数据量大的时候很麻烦;看不出递归调用的次数,看不出物理读的多少(不过逻辑读才是重点)
五、dbms_xplan.display_cursor('&sql_id')
1.获取到sql_id
2.执行查询SQL
select * from table(dbms_xplan.display_cursor('&sqlId'));
优点:不用执行SQL,只需要知道SQL_ID;真实的执行计划;
缺点:没有相关统计信息;没办法看到表被访问多少次;没办法看到处理多少行
六、10046 trace跟踪
1.开启10046 trace
alter session set events '10046 trace name context forever,level 12';
2.执行SQL
3.关闭10046 trace
alter session set events '10046 trace name context off';
4.查找trace文件路径,获取trace文件
优点:可以看到SQL对应的等待时间;可以看出执行的统计信息;可以看到解析时间和执行时间;可以看到函数里面调用的sql的执行计划
缺点:需要登陆数据库服务器,获取并格式化trace文件;没办法看到表被访问多少次;
七、awrsqlrpt.sql
1.@?/rdbms/admin/awrsqrpt.sql
2.选择你要的断点(begin snap 和end snap)
3.输入sql_id
或者
执行SQL
SELECT output FROM TABLE(dbms_workload_repository.awr_sql_report_html(l_dbid => 1045358809, l_inst_num => 1, l_bid => 4457, l_eid => 4463, l_sqlid => 'cgc37m709dvm4'));
八、sql_monitor
sql_monitor是oracle数据库11g引进的特性,通过sqlmonitor可以在sql运行中看他们的实际执行计划。
SELECT m.sql_text, dbms_sqltune.report_sql_monitor(sql_id => m.sql_id, TYPE => 'HTML', report_level => 'ALL') AS report FROM gv$sql_monitor m WHERE 1 = 1 /*and m.sid = 2015 AND m.session_serial# = 30119*/ AND (m.sid, m.session_serial#) IN (SELECT s.sid, s.serial# FROM fnd_concurrent_requests fcr, gv$session s WHERE fcr.request_id = 126796916 AND fcr.oracle_session_id = s.audsid) ORDER BY 1;
总结:
1.如果某SQL执行非常长时间才会出结果,甚至慢到返回不了结果,这时候看执行计划就只能用方法1和 方法2;
2.跟踪某条SQL最简单的方法是方法1、2,其次就是方法3;
3.如果想观察到某条SQL有多条执行计划的情况,只能用方法5和方法7;
4.如果SQL中含有多函数,函数中套有SQL等多层递归调用,想准确分析,只能使用方法6;
5.要想确保看到真实的执行计划,不能用方法1和方法2、3;
6.要想获取表被访问的次数,只能使用方法4;
补充说明: v$sql和v$sqlarea
v$sqlarea和v$sql两个视图的不同之处在于,v$sql中为每一条SQL保留一个条目,而v$sqlarea中根据sql_text进行group by,通过version_count计算子指针的个数。
v$sql视图列举了共享SQL区(Shared SQL Area)中的SQL统计信息,这个视图中的信息未经分组,每个SQL指针都包含一条独立的记录
字段:
Column
|
Datatype
|
Descrption
|
SQL_TEXT | VARCHAR2(1000) | 当前SQL指针的前1000个字符(也就是说这里记录的SQL是不完整的) |
EXECUTIONS | NUMBER | 执行次数 |
DISK_READS | NUMBER | 这个子指针Disk Read的次数 |
BUFFER_GETS | NUMBER | 这个子指针的Buffer Gets数量 |
OPTIMIZER_MODE | VARCHAR2(10) | SQL执行的优化器模式 |
OPTIMIZER_COST | NUMBER | SQL执行成本 |
HASH_VALUE | NUMBER | 在Library Cache中父指针的Hash Value值 |
SQL第一次执行时,SQL的HASH_VALUE被计算出来,并且随之,这个SQL的父指针(Parent Cursor)在内存中被创建,一个子指针同时创建。父指针可以被认为是Hash Value的相关信息,子指针可以被认为是SQL的元数据。
再次执行这个查询,统计信息中的物理读(DISK_READS)不再增加,因为数据已经在Buffer中存在,而BUFFER_GETS继续增加。执行次数也变为2次:
v$sqlarea列出了共享SQL区(Shared SQL Area)中的SQL统计信息,这些SQL按照SQL文本的不同,每条会记录一行统计数据
Column
|
Datatype
|
Description
|
SQL_TEXT | VARCHAR2(1000) | 当前指针的前1000个字符 |
VERSION_COUNT | NUMBER | Cache中这个父指针下存在的子指针的数量 |
EXECUTIONS | NUMBER | 总的执行次数,包含所有子指针执行次数的汇总 |
DISK_READS | NUMBER | 所有子指针的Disk Reads总和 |
BUFFER_GETS | NUMBER | 所有子指针的Buffer Gets总和 |
OPTIMIZER_MODE | VARCHAR2(10) | SQL执行的优化器模 |
HASH_VALUE | NUMBER | 父指针的Hash Value |