注意事项:
1.使用DDL操作可以让ORACLE再次执行目标SQL时使用硬解析,但其影响范围太广,因为一旦对某个表执行了DDL操作,再次执行与这个表相关的所有SQL时就会全部使用硬解析。
这是很不好的,特别是对于OLTP类型的应用系统而言,因为这可能会导致短时间内硬解析数量剧增,进而影响系统的性能。
2.可以使用DBMS_SHARED_POOL.PURGE来删除指定的缓存在库缓存中的Shared Cursor,该方式影响范围仅限于该目标SQL所对应的Shared Cursor,
也就是说它可以做到只让Oracle在执行目标SQL时使用硬解析,在执行所有其他SQL时都和原来一样保持不变。
SQL> SELECT SQL_TEXT,SQL_ID,ADDRESS,HASH_VALUE FROM v$SQLAREA WHERE SQL_TEXT LIKE 'SELECT COUNT(*) FROM T1%';
SQL> EXEC SYS.DBMS_SHARED_POOL.PURGE('address,hash_value','c') --其中这里第二个输入参数是常量c,表示要删除的是Shared Cursor。
3.Child Cursor中除了会存储目标SQL的解析树和执行计划之外,还会存储该SQL所使用的绑定变量的类型和长度,这意味着即使该SQL的SQL文本没有发生任何改变,
只要其SQL文本中文本型绑定变量的定义发生了改变,那么该SQL再次执行时可能还是做了硬解析(参考3.2.5 绑定变量分级)
第一种方式:explain plan命令
explain plan for +目标SQL
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY)
补充:SELECT DBMS_METADATA.GET_DDL('TABLE','PLAN_TABLES$','SYS') FROM DUAL --查看原代码
SELECT SID FROM v$MYSTAT WHERE ROWNUM<2; --查看当前SESSION的SESSION ID
第二种方式:DBMS_XPLAN包
A.用于在SQLPLUS中查看刚刚执行过的SQL的执行计划
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'ADVANCED'))
B.用于查看指定SQL的执行计划(只要目标SQL的执行计划所在的Child Cursor还没有被age out出Shared Pool,就可以用这种方法来查看该SQL的执行计划)
SQL>SELECT SQL_TEXT,SQL_ID,HASH_VALUE,CHILD_NUMBER FROM v$SQL WHERE SQL_TEXT LIKE 'SELECT EMPNO,ENAME%';
/* 只要目标SQL所对应的Child Cursor还在Library Cache中,我们就可以从v$SQL中查到目标SQL的Child Cursor的详细信息,包括SQL ID,SQL HASH VALUE,Child Cursor Number等
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('sql_id/hash_value',child_cursor_number,'ADVANCED')) ;
案例:SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('3yfu3wh150aqt','0','ADVANCED')) ;
C.用于查看指定SQL的所有历史执行计划。
使用方法A、B能够显示目标SQL执行计划的前提条件是该SQL的执行计划还在Shared Pool中,而如果该SQL的执行计划已经被age out出Shared Pool,
那么只有该SQL的执行计划被ORACLE采集到AWR Repository中,我们就可以使用方法C来查看该SQL的所有历史执行计划。
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('79glp919t7x4u')) ;
案例:模拟实验环境
1.手工收集一下AWR报告,采集完成后清空Shared Pool
SQL> EXEC DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT();
SQL> ALTER SYSTEM FLUSH SHARED_POOL; --请勿随意在生产环境执行此语句
2.查看目标SQL的执行计划是否被age out出Shared Pool了
SQL> SELECT SQL_TEXT,SQL_ID,VERSION_COUNT,EXECUTIONS FROM v$SQLAREA WHERE SQL_TEXT LIKE 'SELECT COUNT(*) FROM T1%'; --此时已没有记录了
3.由于之前我们已经通过手工采集AWR报告的方式将目标SQL的执行计划采集到了AWR Repository中,所以现在我们可以通过执行方法C来得到该SQL的所有历史执行计划:
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR('79glp919t7x4u')) ;
第三种方式:AUTOTRACE开关
SQL> set autot ?
Usage: SET AUTOT[RACE] {OFF | ON | TRACE[ONLY]} [EXP[LAIN]] [STAT[ISTICS]]
SQL>SET AUTOTRACE OFF (set autot off) 不显示 只有查询结果
SET AUTOTRACE ON (set autot on) 启动 : 查询结果 执行计划 统计信息
SET AUTOTRACE TRACEONLY(set autot trace) :不显示查询结果 只显示:执行结果数量 执行计划 统计信息
SET AUTOTRACE TRACEONLY EXPLAN (set autot trace exp) ;;:只显示:执行计划
SET AUTOTRACE TRACEONLY STATISTICS(set autot trace stat) ; 只显示 :执行结果数量 统计信息
缺陷:1.必须要等到语句真正执行完毕后,才可以出结果
2.无法看到表被访问了多少次。
第四种方式:statistics_level=all (可以看到表的访问次数)
SQL> alter session set statistics_level=all;
SQL> 执行语句
SQL> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
第五种方式:10046事件
优点:1.可以看出SQL语句对应的等待事件。
2.如果SQL语句中有函数调用,SQL中有SQL,将会都被列出,无所遁形。
3.可以方便的看出处理的行数,产生的逻辑读。
4.可以方便的看出解析时间和执行时间。
5.可以跟踪整个程序包。
缺陷:1.无法判断表被访问了多少次。
2.步骤繁琐。
3.执行计划中的谓词部分不能清晰的展示出来。
第六种方式;AWR SQL报告
A.先根据AWR报告找到目标SQL
生成AWR报告
SQL>@?\rdbms\admin\awrrpt.sql
B.手工执行脚本$ORACLE_HOME/rdbms/admin/awrsqrpt.sql,并依次输入报告类型、要查看的快照范围、目标SQL ID和所有生成的AWR SQL报告的名称;
SQL> @?\rdbms\admin\awrsqrpt.sql';(建议的快照范围和AWR报告的范围一致)
--------------------------------额外补充--------------------------------------------------
非dba用户set autotrace提示启用 STATISTICS 报告时出错
创建plustrace角色,然后将角色赋给特定用户。Oracle已经提供了角色plustrace的创建脚本
@/u01/app/oracle/product/11.2.0/dbhome_1/sqlplus/admin/plustrce.sql
把角色赋权给zw用户
SQL> grant plustrace to zw;
SQL> conn zw/zw
Connected.
SQL> set autotrace traceonly;
把角色赋予给所有用户
SQL> grant plustrace to public;