1. 程式人生 > >為什麼v$sql中的執行次數會被重置

為什麼v$sql中的執行次數會被重置

這幾天一直在觀察生產環境中一個長時間執行的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)很可能是定時的表分析使統計資料發生了變化,從而導致了新子游標的產生。。。希望明天去公司能夠證實我的想法。。