有时候,需要测试SQL的性能,但是运行过的SQL会在共享池中生成执行计划,如何精确的清除SQL语句执行计划?
注意:在11g中,好像只有sys和system两个账户可以使用这个存储过程。
执行SQL语句
select count(1) from abc ;
显示结果:
查询共享池中该SQL语句的执行计划:
select SQL_TEXT,sql_id, address, hash_value, executions, loads, parse_calls, invalidations
from v$sqlarea V
where v.SQL_TEXT like '%select count(*) from abc%';
显示执行结果:
执行dbms_shared_pool.purge清除执行计划:
call sys.dbms_shared_pool.purge('BE988DB4,1573609778','c')
执行成功!!!
再次查看该语句的执行计划是否存在,显示结果:
过程PURGE的第一个参数为V$SQLAREA中用逗号分隔的ADDRESS列和HASH_VALUE列的值,第二个参数'C'表示PURGE的对象是CURSOR(游标),不过实际上这里可以使用除了P(PROCEDURE/FUNCTION/PACKAGE)、T(TYPE)、R(TRIGGER)和Q(SEQUENCE)的任何值。
使用这种方法,就可以精确的将一个SQL从共享池中删除,从而使得Oracle为这个SQL重新生成执行计划。这种方法只针对单个SQL语句,使得解决问题的同时不会造成任何的误伤。
不过需要注意一点,在10.2.0.4中,虽然PURGE过程已经存在,但是要使这个过程可以真正的生效,还必须设置一个EVENT:
SQL> alter system set event = '5614566 trace name context forever' scope = spfile;
System altered.
设置EVENT后需要重启,DBMS_SHARED_POOL的PURGE才可以生效。也就是说,除非提前进行过设置,否则这个PURGE的功能对于一个产品环境而言,必须在10.2.0.5以上版本才可以使用。