"flush shared_pool" "version_count过高引起的bug"

数据库版本:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production

数据库现象:
负载瞬间从原来的1左右涨到35左右,持续约几十秒,逐步降到正常水平。当时的top里面cup-user已经达到将近100%,iowait正常。
做了当时的ash报告:大部分等待是cursor.mutex S的。
'flush <wbr>shared_pool' <wbr>'version_count过高引起的bug'

'flush <wbr>shared_pool' <wbr>'version_count过高引起的bug'

AWR报告:
'flush <wbr>shared_pool' <wbr>'version_count过高引起的bug'
同事数据库抱这种错误:
Process m000 died, see its trace file
Fri Mar 28 17:44:14 2014
Exception [type: SIGSEGV, Address not mapped to object] [ADDR:0x8] [PC:0x824232C, ksmdget()+1144] [flags: 0x0, count: 1]
Errors in file /home/oracle/app/oracle/diag/rdbms/rep_std/rep/trace/rep_ora_27410.trc   (incident=307401):
ORA-07445: exception encountered: core dump [ksmdget()+1144] [SIGSEGV] [ADDR:0x8] [PC:0x824232C] [Address not mapped to object] []
Fri Mar 28 17:44:17 2014
Exception [type: SIGSEGV, Address not mapped to object] [ADDR:0x8] [PC:0x824232C, ksmdget()+1144] [flags: 0x0, count: 1]
Errors in file /home/oracle/app/oracle/diag/rdbms/rep_std/rep/trace/rep_ora_27442.trc   (incident=307402):
ORA-07445: exception encountered: core dump [ksmdget()+1144] [SIGSEGV] [ADDR:0x8] [PC:0x824232C] [Address not mapped to object] []
Fri Mar 28 17:44:20 2014
Exception [type: SIGSEGV, Address not mapped to object] [ADDR:0x8] [PC:0x824232C, ksmdget()+1144] [flags: 0x0, count: 1]
Errors in file /home/oracle/app/oracle/diag/rdbms/rep_std/rep/trace/rep_ora_27474.trc   (incident=307403):
ORA-07445: exception encountered: core dump [ksmdget()+1144] [SIGSEGV] [ADDR:0x8] [PC:0x824232C] [Address not mapped to object] []
Fri Mar 28 17:45:14 2014


sys@REP>select sql_id,version_count from v$sqlarea where version_count>500 order by 2;
 
SQL_ID                                        VERSION_COUNT
-------------------------- -------------    
akh9zqqkx3wj7                                              505
8p9z2ztb272bm                                              549
dxhynxuvpdckh                                              585
23nad9x295gkf                                              645
9m8u3xjk22n2q                                              949
f447xkq6k3wqh                                            1178
8q2sy7qbwnuxc                                            1259
4wdvmft15nkxq                                            1899
3h20hzddhy0qg                                            1914
fn6691ycv3twx                                            2105
9h38vus0vxd8c                                            2262
8dq1u5tw7ssdc                                            4314
83vn6pv4x6034                                            8137
apcvzv8w0v1dj                                          16411
具有很高version的sql。根据现象判断,很想oracle描述的一个bug。
参考:
http://www.itpub.net/thread-1390779-1-1.html
http://prefectliu.blog.163.com/blog/static/2363081820123652347371/
http://blog.csdn.net/mybluetiankong/article/details/18548249


如果您发现自己有大量 cursor 版本,参阅以下文章可能会有所帮助:

Note:296377.1  Troubleshooting: High Version Count Issues
Note:438755.1  Formated V$SQL_SHARED_CURSOR Report by SQLID or Hash Value


Version Count 数目过多诊断的方法

1、关于version count

 首先我们一起来回顾一下Oracle的“父子游标”(child cursor and parent cursor)概念。Oracle中,任何一个执行的SQL语句,都会以游标cursor的形式进行处理。具体来说,一个SQL要涉及到两个游标对象,共享游标shared cursor和私有游标private cursor

 Private cursor是驻留在Oracle Server Process PGA内部,只能被一个Server Process对应的会话使用。而shared cursor驻留在SGAshared pool中,具体位于shared pool中的library cache

 shared cursor而言,主要缓存的目的在于执行计划的共享。一个SQL经过validateparse过程,会形成父游标和子游标的配对组合。SQL文本完全相同的语句,会共享父游标。而环境信息、对象信息相同的SQL语句,才可能共享子游标。当找不到对应的子游标或者父游标时,也就意味着找不到可共享的执行计划。这样对应的SQL就需要发生hard parse,重新生成执行计划。

 

一个父游标下对应的子游标个数,我们成为version count。每一个

子游标对应一个执行计划对象

 version count就表示当前父游标下对应子游标的个数。如果一个父游标对应的子游标version count过多,也就是对应了很多的子游标对象。这样,当server process检查可共享的游标时,就需要长时间的检索子游标列表。

 

最有名的version count过多问题是由于设置cursor_sharing参数为similar后,引发的version count错误。

 

此外,version count过多也是我们需要诊断SQL为什么不会共享的一个出发点。比较常用的有两种,本篇中进行详细介绍:

2v$sql_shared_cursor视图

 SQL执行计划的生成,是受到很多因素影响的。相同父游标只是表示输入SQL的字面值相同。子游标对应的因素,如优化器类型、optimizer_mode、对应对象权限等的差异,都会影响到子游标的共享。

 

Oracle 11g中,一个新的视图被提供出来,用于帮助诊断子游标不共享问题的原因,就是v$sql_shared_cursor

该视图是一个宽列视图,通过sql_idchild_number就可以定义某个特定子游标的信息。其他大部分列都是以varchar2(1)Y/N取值,每列的含义都是一个不能共享的理由。注意:这个理由N表示的是不能共享第一个子游标child_number=0的理由。 

3version-rpt脚本 

MOS438755.1中,Oracle提供了一个专门的脚本程序,用于协助诊断high SQL version count问题。

 首先,我们需要从MOS上下载到脚本version_rpt.sql,目前笔者的版本为3.1.2。使用sys用户登录之后,调用该脚本创建相应的数据库对象。

4、结论

 version count问题是Oracle SQL共享的一个方面。借助适当的工具手段,我们可以准确的定位问题,解决问题。


flush a sql out off shared_pool

起初想刷出一个sql,方法类似于下面:
在11G之前(准确的说在10204之前),当我们需要flush一些literal SQL out of shared pool时,我们马上想到的是对于这个SQL所在的object上做一些DDL使其马上被flush出shared pool。例如:
comment on table ... is '';
grant select on  table  to sys;
但是11G开始这招不灵了。
做DDL只是将这个objects相关的SQL标志为INVALID,然后下次执行时才被清除。

select ADDRESS,HASH_VALUE,EXECUTIONS,SHARABLE_MEM,OBJECT_STATUS from v$sqlarea where SQL_TEXT like 'select count(*) from testsqlsql%';
一般情况下是没问题的,但是如果我们希望flush一些literal SQL或者占用shared pool非常之大的SQL,而且希望他们马上消失,这时我们需要其他的办法。
就是11G的 dbms_shared_pool.purge。 (准确的说10204就有了,只是有一些bug)。

不过需要注意一点,在10.2.0.4中,虽然PURGE过程已经存在,但是要使这个过程可以真正的生效,还必须设置一个EVENT

SQL> alter system set event = '5614566 trace name context forever' scope = spfile;

设置EVENT后需要重启,DBMS_SHARED_POOLPURGE才可以生效。也就是说,除非提前进行过设置,否则这个PURGE的功能对于一个产品环境而言,必须在10.2.0.5以上版本才可以使用。

PROCEDURE PURGE
Argument Name                  Type                    In/Out Default?
------------------------------ ----------------------- ------ --------
NAME                           VARCHAR2                IN
FLAG                           CHAR                    IN     DEFAULT
HEAPS                          NUMBER                  IN     DEFAULT

如果对于SQL cursor来说,NAME参数的格式是ADDR,HASH_VALUE from v$sqlarea。
FLAG参数标明了NAME参数的种类,对于SQL Cursor来说,FLAG只要不为'P' or 'p' or 'Q' or 'q' or 'R' or 'r' or 'T' or 't'即可。所以在其他的文章中,为了flush一个SQL Cursor,FLAG常被设为'C',其实设为其他任何字母都没问题。
HEAPS参数为1代表所有heaps都被purge。即:
select ADDRESS,HASH_VALUE,EXECUTIONS,SHARABLE_MEM,OBJECT_STATUS from v$sqlarea where SQL_id='';

exec dbms_shared_pool.purge('00000004D3F4C760,940410289','C');
exec sys.dbms_shared_pool.purge('000000039FCBEBE0,4184050671','C',1);

通常情况下,这中方法就应该可以了,但这次不行,执行完之后,shared_pool里面还有,并且object_status还显示valid。

之后使用下面的方法,使得执行计划无效:
exec dbms_stats.gather_table_stats('USER','TABLE_NAME',cascade=>true,estimate_percent=>0.00001,no_invalidate=>false);  
结果还是不行。。。。。。。。
但刷出整个shared_pool,白天业务比较繁忙,又不太敢做。。。。。
最后,让开发人员先把读应用切换到从库上面,然后再在主库上执行:
alter system flush shared_pool;(瞬秒)

之后在查看v$sqlarea,version_count都很低了,都是些新load的sql。

Bug 9689310 - Excessive child cursors / high VERSION_COUNT / ORA-600 [17059] due to bind mismatch (文档 ID 9689310.8)
该问题要彻底解决,还需要进行数据库版本的升级!

参考:
http://blog.itpub.net/15415488/viewspace-627066/
http://www.2cto.com/database/201204/126388.html
http://hi.baidu.com/dba_hui/item/3dc8870d0a801102acdc7002
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值