如果Oracle的优化器产生了某种错误的执行计划,或者我们希望Oracle对于某个SQL重新进行分析,那么就需要这个SQL的执行计划在共享池中过期,而简单的方法在10.2.0.4以后才出现。
对于以前的版本而言,最显而易见的方法莫过于直接刷新共享池,但是如果是
数据库中绝大部分的SQL都存在问题,那么这种方法无可厚非,也可能是见效最快的方法,而如果数据库中仅仅是个别的SQL存在问题,那么这种方法就过于暴力了。
SQL> select count(*) from dual;
COUNT(*)
----------
1
SQL> select sql_id, address, hash_value, executions, loads, parse_calls, invalidations
2 from v$sqlarea www.2cto.com
3 where sql_text = 'select count(*) from dual';
SQL_ID ADDRESS HASH_VALUE EXECUTIONS LOADS PARSE_CALLS INVALIDATIONS
------------- ---------------- ---------- ---------- ---------- ----------- -------------
4m94ckmu16f9k 00000000B6C61FC0 4094900530 1 1 1 0
SQL> select count(*) from v$sqlarea;
COUNT(*)
----------
3061
SQL> alter system flush shared_pool;
System altered.
SQL> select sql_id, address, hash_value, executions, loads, parse_calls, invalidations
2 from v$sqlarea
3 where sql_text = 'select count(*) from dual';
no rows selected
SQL> select count(*) from v$sqlarea;
COUNT(*)
----------
37
为了一个SQL而清空整个共享池,这个代价确实太大了,何况对于一个繁忙的OLTP系统而言,这个刷新共享池的操作所带来的风险和后果与直接关闭数据库相比,也没有太大的差别。
那么有没有细粒度一点的办法呢,其实方法有很多,相关表上任何的DDL都会导致SQL执行计划的失效,但是DDL本身风险就毕竟高,如果想要对系统影响最小,那么这个DDL就非GRANT莫属。只需要当前用户将这个表的权限授权给自己,就可以达到想要的效果:
SQL> select count(*) from dual;
COUNT(*)
----------
1
SQL> select sql_id, address, hash_value, executions, loads, parse_calls, invalidations
2 from v$sqlarea www.2cto.com
3 where sql_text = 'select count(*) from dual';
SQL_ID ADDRESS HASH_VALUE EXECUTIONS LOADS PARSE_CALLS INVALIDATIONS
------------- ---------------- ---------- ---------- ---------- ----------- -------------
4m94ckmu16f9k 00000000B6C61FC0 4094900530 1 1 1 0
SQL> select 1 from dual;
1
----------
1
SQL> select * from dual;
D
-
X
SQL> select 'a' from dual;
'
-
a
SQL> select count(1) from dual;
COUNT(1)
----------
1
SQL> select sql_id, address, hash_value, executions, loads, parse_calls, invalidations
2 from v$sqlarea www.2cto.com
3 where lower(sql_text) like '%dual%';
SQL_ID ADDRESS HASH_VALUE EXECUTIONS LOADS PARSE_CALLS INVALIDATIONS
------------- ---------------- ---------- ---------- ---------- ----------- -------------
gr7s3j0cg8pr6 00000000B6A5A470 418666214 1 1 1 0
40p7rprfbt1as 00000000B69BDC38 3703342424 1 1 1 0
520mkxqpf15q8 00000000B6DD9610 2866845384 1 1 1 0
ak90gdq0udv37 00000000B6E3C6B0 2175200359 2 2 2 1
4m94ckmu16f9k 00000000B6C61FC0 4094900530 1 1 1 0
a5ks9fhw2v9s1 00000000B698DA88 942515969 1 1 1 0
800hwktjz3zuc 00000000B6999268 1676803916 1 1 1 0
7 rows selected.
SQL> grant select on dual to sys;
grant select on dual to sys
*
ERROR at line 1:
ORA-01749: you may not GRANT/REVOKE privileges to/from yourself
SQL> grant select on dual to public;
Grant succeeded.
SQL> select sql_id, address, hash_value, executions, loads, parse_calls, invalidations
2 from v$sqlarea www.2cto.com
3 where lower(sql_text) like '%dual%';
SQL_ID ADDRESS HASH_VALUE EXECUTIONS LOADS PARSE_CALLS INVALIDATIONS
------------- ---------------- ---------- ---------- ---------- -----------