您的位置:首页 > 数据库

为什么v$sql中的执行次数会被重置

2014-06-22 22:06 232 查看
这几天一直在观察生产环境中一个长时间执行的sql,我是用select * from v$sql where sql_id=*** 去观察的。因为这个sql是游标里面的语句,通过它执行的次数,我可以判断这个程序大概什么时候可以执行完毕。就在隔了一天,我再次用这个语句观察sql的执行次数时发现EXECUTIONS被重置了,数量比我前天观察到的小很多(在v$sql中通过sqlid只有一行数据),但是这个程序还在运行!我当时观察了 v$sql
的FIRST_LOAD_TIME,LAST_LOAD_TIME时间,前一个是sql开始执行的时间,这个没问题,后一个时间是凌晨时间,也就是说,凌晨的时候这个sql被重新加载了!我当时没想明白为什么会重新加载,今天看了篇有关父游标和子游标的文章后,才明白可能是sqlid在执行时,产生了子游标!!!!!

首先简单说明下父游标和子游标:

1. oracle是一个采用共享机制的数据库,如果sql能够共享,它是不会重新生成游标的(包括父游标和子游标);

2. 一个sql在首次被加载时,一定是产生一个父游标和一个子游标,V$SQL可以观察子游标,v$sqlarea可以观察父游标

SELECT T.FIRST_LOAD_TIME,
T.LAST_LOAD_TIME,
T.LAST_ACTIVE_TIME,
T.CHILD_NUMBER,
T.LOADS,
T.EXECUTIONS,
T.CHILD_ADDRESS
FROM V$SQL T
WHERE T.SQL_ID = 'gvhnpfk1ytyh3';
SELECT T.SQL_ID,
T.EXECUTIONS,
T.LOADED_VERSIONS,
T.LOADS,
T.ADDRESS
FROM V$SQLAREA T
WHERE T.SQL_ID = 'gvhnpfk1ytyh3';
V$SQL中的FIRST_LOAD_TIME是表示父游标的加载时间,LAST_LOAD_TIME表示对应子游标的加载时间,child_number表示子游标的编号(从0开始);
v$sqlarea中的EXECUTIONS是父游标下面全部子游标总共的执行次数(其实我应该从这里来观察总的执行次数)LOADED_VERSIONS表示有几个子游标。

所以通过V$SQL中的LAST_LOAD_TIME时间的变化,应该可以判断出来确实产生了新的子游标,从而导致EXECUTIONS被重置(这个时候的EXECUTIONS是新的子游标执行的次数)。解决了EXECUTIONS被重置的问题后,又引出了2个问题:1.为什么在V$SQL中我通过sqlid只看到一行记录;2.
是什么原因导致了正在执行的sql产生了新的子游标?

第一个问题,可能是因为前一个子游标因为空闲被置换出了内存;

第二个问题,可以通过一个视图来寻找答案:v$sql_shared_cursor

SELECT * FROM v$sql_shared_cursor t WHERE t.SQL_ID='gvhnpfk1ytyh3';

这个视图记录了每个子游标产生的原因(即sql不能共享的原因),通过帮助文档,我观察到其中有个原因很可能就是这次sql产生子游标的原因:STATS_ROW_MISMATCH(The existing statistics do not match the existing child cursor)很可能是定时的表分析使统计数据发生了变化,从而导致了新子游标的产生。。。希望明天去公司能够证实我的想法。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: