Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
数据库现象:
负载瞬间从原来的1左右涨到35左右,持续约几十秒,逐步降到正常水平。当时的top里面cup-user已经达到将近100%,iowait正常。
做了当时的ash报告:大部分等待是cursor.mutex S的。
AWR报告:
同事数据库抱这种错误:
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驻留在SGA的shared pool中,具体位于shared pool中的library cache。
对shared cursor而言,主要缓存的目的在于执行计划的共享。一个SQL经过validate和parse过程,会形成父游标和子游标的配对组合。SQL文本完全相同的语句,会共享父游标。而环境信息、对象信息相同的SQL语句,才可能共享子游标。当找不到对应的子游标或者父游标时,也就意味着找不到可共享的执行计划。这样对应的SQL就需要发生hard parse,重新生成执行计划。
一个父游标下对应的子游标个数,我们成为version count。每一个
子游标对应一个执行计划对象。
version count就表示当前父游标下对应子游标的个数。如果一个父游标对应的子游标version count过多,也就是对应了很多的子游标对象。这样,当server process检查可共享的游标时,就需要长时间的检索子游标列表。
最有名的version count过多问题是由于设置cursor_sharing参数为similar后,引发的version count错误。
此外,version count过多也是我们需要诊断SQL为什么不会共享的一个出发点。比较常用的有两种,本篇中进行详细介绍:
2、v$sql_shared_cursor视图
SQL执行计划的生成,是受到很多因素影响的。相同父游标只是表示输入SQL的字面值相同。子游标对应的因素,如优化器类型、optimizer_mode、对应对象权限等的差异,都会影响到子游标的共享。
在Oracle 11g中,一个新的视图被提供出来,用于帮助诊断子游标不共享问题的原因,就是v$sql_shared_cursor。
该视图是一个宽列视图,通过sql_id和child_number就可以定义某个特定子游标的信息。其他大部分列都是以varchar2(1)的Y/N取值,每列的含义都是一个不能共享的理由。注意:这个理由N表示的是不能共享第一个子游标child_number=0的理由。
3、version-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_POOL的PURGE才可以生效。也就是说,除非提前进行过设置,否则这个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