如果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
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
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 
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
3 where lower(sql_text) like '%dual%';
 
SQL_ID ADDRESS HASH_VALUE EXECUTIONS LOADS PARSE_CALLS INVALIDATIONS
------------- ---------------- ---------- ---------- ---------- ----------- -------------
gr7s3j0cg8pr6 00000000B6A5A470 418666214 2 1 2 0
ak90gdq0udv37 00000000B6E3C6B0 2175200359 2 2 2 1
 
对于其他用户而言,都可以使用将表的查询权限授权给OWNER本身的方法,但是测试用户本身为SYS,因此需要其他用户授权,方便起见使用了授权给PUBLIC的方式。可以看到,这种方式同样可以生效,但是仍然存在打击面过大的问题。对于系统中一个频繁访问的表,很可能这个授权的操作,导致少则几十,多则几百个SQL都是失效,这个风险仍然不可小觑。
 
那么对于就没有一个可以将粒度控制在SQL本身上的方法吗?在11g中,Oracle的DBMS_SHARED_POOL包新增了PURGE功能,可以完美的解决这个问题,这个方法在10.2.0.4和10.2.0.5补丁集中也被添加进来,使得10.2的高版本同样可以实现这个功能,使用方法很简单:
 
SQL> select count(*) from dual;
 
COUNT(*)
----------
1
 
SQL> select sql_id, address, hash_value, executions, loads, parse_calls, invalidations
2 from v$sqlarea
3 where sql_text = 'select count(*) from dual';
 
SQL_ID ADDRESS HASH_VALUE EXECUTIONS LOADS PARSE_CALLS INVALIDATIONS
------------- ---------------- ---------- ---------- ---------- ----------- -------------
4m94ckmu16f9k 00000000B6C61FC0 4094900530 1 2 1 1
 
SQL> select 1 from dual;
 
1
----------
1
 
SQL> select * from dual;
 
D
-
X
 
SQL> select sql_id, address, hash_value, executions, loads, parse_calls, invalidations
2 from v$sqlarea
3 where lower(sql_text) like '%dual%';
 
SQL_ID ADDRESS HASH_VALUE EXECUTIONS LOADS PARSE_CALLS INVALIDATIONS
------------- ---------------- ---------- ---------- ---------- ----------- -------------
gr7s3j0cg8pr6 00000000B6A5A470 418666214 3 1 3 0
520mkxqpf15q8 00000000B6DD9610 2866845384 1 2 1 1
ak90gdq0udv37 00000000B6E3C6B0 2175200359 3 2 3 1
4m94ckmu16f9k 00000000B6C61FC0 4094900530 1 2 1 1
a5ks9fhw2v9s1 00000000B698DA88 942515969 1 2 1 1
 
SQL> exec dbms_shared_pool.purge('00000000B6C61FC0,4094900530', 'c')
 
PL/SQL procedure successfully completed.
 
SQL> select sql_id, address, hash_value, executions, loads, parse_calls, invalidations
2 from v$sqlarea
3 where lower(sql_text) like '%dual%';
 
SQL_ID ADDRESS HASH_VALUE EXECUTIONS LOADS PARSE_CALLS INVALIDATIONS
------------- ---------------- ---------- ---------- ---------- ----------- -------------
gr7s3j0cg8pr6 00000000B6A5A470 418666214 4 1 4 0
520mkxqpf15q8 00000000B6DD9610 2866845384 1 2 1 1
ak90gdq0udv37 00000000B6E3C6B0 2175200359 3 2 3 1
a5ks9fhw2v9s1 00000000B698DA88 942515969 1 2 1 1
 
过程PURGE的第一个参数为V$SQLAREA中用逗号分隔的ADDRESS列和HASH_VALUE列的值,第二个参数’c’表示PURGE的对象是CURSOR,不过实际上这里可以使用除了P(PROCEDURE/FUNCTION/PACKAGE)、T(TYPE)、R(TRIGGER)和Q(SEQUENCE)的任何值  www.2cto.com  
 
使用这种方法,就可以精确的将一个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以上版本才可以使用。

将指定SQL的执行计划从共享池删除的方法的更多相关文章

  1. ORACLE从共享池删除指定SQL的执行计划

    Oracle 11g在DBMS_SHARED_POOL包中引入了一个名为PURGE的新存储过程,用于从对象库缓存中刷新特定对象,例如游标,包,序列,触发器等.也就是说可以删除.清理特定SQL的执行计划 ...

  2. Oracle 从共享池删除指定SQL的执行计划

    ORACLE从共享池删除指定SQL的执行计划 2016-12-29 11:14 by 潇湘隐者, 2836 阅读, 0 评论, 收藏, 编辑 Oracle 11g在DBMS_SHARED_POOL包中 ...

  3. SQL Server 执行计划缓存

    标签:SQL SERVER/MSSQL SERVER/数据库/DBA/内存池/缓冲区 概述 了解执行计划对数据库性能分析很重要,其中涉及到了语句性能分析与存储,这也是写这篇文章的目的,在了解执行计划之 ...

  4. 如何清除某条SQL的执行计划

    如果遇到绑定窥探导致执行计划慢的情况,想要清除某条SQL的执行计划,让它硬解析,找了很久都没有找到直接操作share pool的方法(除非alter system flush shared_pool) ...

  5. Oracle之SQL优化专题03-如何看懂SQL的执行计划

    专题第一篇<Oracle之SQL优化专题01-查看SQL执行计划的方法>讲到了查看SQL执行计划的方法,并介绍了各种方法的应用场景,那么这一篇就主要介绍下如何看懂SQL的执行计划.毕竟如果 ...

  6. 浅析SQL SERVER执行计划中的各类怪相

    在查看执行计划或调优过程中,执行计划里面有些现象总会让人有些疑惑不解: 1:为什么同一条SQL语句有时候会走索引查找,有时候SQL脚本又不走索引查找,反而走全表扫描? 2:同一条SQL语句,查询条件的 ...

  7. sql server 执行计划(execution plan)介绍

    大纲:目的介绍sql server 中执行计划的大致使用,当遇到查询性能瓶颈时,可以发挥用处,而且带有比较详细的学习文档和计划,阅读者可以按照我计划进行,从而达到对执行计划一个比较系统的学习. 什么是 ...

  8. SQL Server 执行计划中的扫描方式举例说明

    SQL Server 执行计划中的扫描方式举例说明 原文地址:http://www.cnblogs.com/zihunqingxin/p/3201155.html 1.执行计划使用方式 选中需要执行的 ...

  9. EXPLAIN PLAN获取SQL语句执行计划

    一.获取SQL语句执行计划的方式 1. 使用explain plan 将执行计划加载到表plan_table,然后查询该表来获取预估的执行计划 2. 启用执行计划跟踪功能,即autotrace功能 3 ...

随机推荐

  1. (转载)【C++】new A和new A()的区别详解

    (转载)http://blog.csdn.net/xiajun07061225/article/details/8796257 我们在C++程序中经常看到两种new的使用方式:new A以及new A ...

  2. 在.net中用Connection对象数据源的架构信息

    可得到数据库中的,表,视图,等信息   string strcon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source = " + fi ...

  3. Breaking parallel loops in .NET C# using the Stop method z

    List<, , , , , , , , , }; Parallel.ForEach(integers, (int item, ParallelLoopState state) => { ...

  4. C#发送简单的HTTP POST请求给传统的ASP网页。

    设计思路 创建HTTPWebRequest类的一个实例,设置这个对象的Method属性为"POST",ContentType属性为"application/x-/www- ...

  5. Flash 导出图片和声音

    命令文件 PolarBear_jsfl.zip Flash Professional 编辑器命令,用来导出 flash 库中的图片和声音 使用步骤: 1. 首先下载 PolarBear_jsfl.zi ...

  6. 初识SQL注入

    什么是SQL注入(SQL Injection)? SQL注入是网站攻击途径之一,这里引用一下百度百科的解释:“所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串, ...

  7. MFC中Listbox控件的简单使用

    MFC中listbox控件是为了显示一系列的文本,每个文本占一行.   Listbox控件可以设置属性为: LBS_CHILD   :(默认)子窗口 LBS_Visible :(默认)可视 LBS_M ...

  8. Petshop学习第二天

    数据访问层的数据访问设计 1.数据层的内容: 数据库访问.Messaging.membership.Profile四部分 2.数据库对象的分类: 一类:数据实体,对应数据库中相应的数据表,它们作为数据 ...

  9. Android实例-LocationSensor位置传感器(XE8+小米2)

    结果: 1.启动后有时会闪退,后来重新做的工程就好了.原因不明(可能与地理反码有关). 2.原文是用的GOOGLE地图显示位置,但在咱们这里好像不行,改为百度,但百度用的是HTML文件.太麻烦了,大家 ...

  10. JS 实现地区,省份,城市,县区4级联动

    刚学JS,实战一下,做一个省份信息4级联动. 但是网上查了都是3级的,没有4级,现在做一个的是带地区的4级联动,最简单的办法是修改别人的代码,最开始找到的事类似于下边这个的: 省市县关联菜单 < ...