{
  "date": "2015-09-30T16:30:55",
  "slug": "query-vundostat-for-relevant-time-window",
  "link": "https://www.dbi-services.com/blog/query-vundostat-for-relevant-time-window/",
  "title": {
    "rendered": "Query V$UNDOSTAT for relevant time window"
  },
  "content": {
    "rendered": "<h2>By Franck Pachot</h2>\n<p>.<br />\nWhen you have a query failing in &#8216;ORA-01555: snapshot too old: rollback segment number &#8230; with name &#8230; too small&#8217; you have two things to do:</p>\n<ol>\n<li>Convince the developer that the rollback segment is not too small because the message text comes from old versions</li>\n<li>Find information about query duration, undo retention and stolen blocks statistics. This is the goal of this post</li>\n</ol>\n<p><!--more--></p>\n<p>The first information comes from the alert.log where every ORA-1555 is logged with the query and the duration:</p>\n<pre><code>Tue Sep 29 19:32:09 2015\nORA-01555 caused by SQL statement below (SQL ID: 374686u5v0qsh, Query Duration=4626 sec, SCN: 0x0022.c823dc12):</code></pre>\n<h3>SCN</h3>\n<p>This means that at 19:32:09 the query 374686u5v0qsh running since  18:15:03 (4626 seconds ago) wasn&#8217;t able to find the undo blocks necessary to build the consistent image as of 18:15:02. How do I know that &#8216;as of&#8217; point-in-time? Usually it&#8217;s the beginning of the query, but there are cases where it can be earlier (in serializable isolation mode, flashback queries) or later (query restart for example).<br />\nIt&#8217;s better to check it: we have the SCN in hexadecimal given as &#8216;base&#8217; and &#8216;wrap&#8217; and we can convert it to a timestamp with the following formula:</p>\n<pre><code>\nSQL&gt; select scn_to_timestamp(to_number('0022','xxxxxxx')*power(2,32)+to_number('c823dc12','xxxxxxxxxxxxxxxxxxxxxx') ) from dual;\n&nbsp;\nSCN_TO_TIMESTAMP(TO_NUMBER('0022','XXXXXXX')*POWER(2,32)+TO_NUMBER('C823D\n-------------------------------------------------------------------------\n29-SEP-15 06.15.02.000000000 PM\n</code></pre>\n<p>Note that there can be a 3 second difference from the precision of SCN_TO_TIMESTAMP.</p>\n<h3>Undo statistics</h3>\n<p>Then I want to know the undo retention:</p>\n<pre><code>\nSQL&gt; show parameter undo_retention\n&nbsp;\nNAME                                 TYPE        VALUE\n------------------------------------ ----------- ------------------------------\nundo_retention                       integer     900\n</code></pre>\n<p>900 seconds means that it is possible to get ORA-1555 after one hour because blocks expire after 15 minutes.</p>\n<p>We can check how the expired undo blocks where reused from V$UNDOSTAT but I use the following query to get only the lines that are relevant to my query (those that cover the query duration up to the ORA-1555 ) and only the non-zero columns:</p>\n<pre><code>\nselect maxqueryid||' '||to_char(end_time,'hh24:mi')||' '||\nrtrim(lower(''\n--||decode(MAXCONCURRENCY,0,'','MAXCONCURRENCY='||MAXCONCURRENCY||' ')\n||decode(UNDOBLKS,0,'','UNDOBLKS='||UNDOBLKS||' ')\n||decode(ACTIVEBLKS,0,'','ACTIVEBLKS='||ACTIVEBLKS||' ')\n||decode(UNEXPIREDBLKS,0,'','UNEXPIREDBLKS='||UNEXPIREDBLKS||' ')\n||decode(EXPIREDBLKS,0,'','EXPIREDBLKS='||EXPIREDBLKS||' ')\n||decode(TUNED_UNDORETENTION,0,'','TUNED_UNDORETENTION(hour)='||to_char(TUNED_UNDORETENTION/60/60,'FM999.9')||' ')\n||decode(UNXPSTEALCNT,0,'','UNXPSTEALCNT='||UNXPSTEALCNT||' ')\n||decode(UNXPBLKRELCNT,0,'','UNXPBLKRELCNT='||UNXPBLKRELCNT||' ')\n||decode(UNXPBLKREUCNT,0,'','UNXPBLKREUCNT='||UNXPBLKREUCNT||' ')\n||decode(EXPSTEALCNT,0,'','EXPSTEALCNT='||EXPSTEALCNT||' ')\n||decode(EXPBLKRELCNT,0,'','EXPBLKRELCNT='||EXPBLKRELCNT||' ')\n||decode(EXPBLKREUCNT,0,'','EXPBLKREUCNT='||EXPBLKREUCNT||' ')\n||decode(SSOLDERRCNT,0,'','SSOLDERRCNT='||SSOLDERRCNT||' ')\n||decode(NOSPACEERRCNT,0,'','NOSPACEERRCNT='||NOSPACEERRCNT||' ')\n)) \"undostats covering ORA-1555\"\n from (\nselect BEGIN_TIME-MAXQUERYLEN/24/60/60 SSOLD_BEGIN_TIME,END_TIME SSOLD_END_TIME from V$UNDOSTAT where SSOLDERRCNT&gt;0\n) , lateral(select * from v$undostat\n where end_time&gt;=ssold_begin_time and begin_time&lt;=ssold_end_time)\norder by end_time;\n/\n</code></pre>\n<p>Lateral join is possible in 12c, but there are other way to do the same in 11g.</p>\n<p>Here is a sample output:</p>\n<pre><code>\nundostats covering ORA-1555\n-------------------------------------------------------------------------------------------------------------\nf3yfg50ga0r8n 18:14 activeblks=224  unexpiredblks=90472 expiredblks=34048 tuned_undoretention(hour)=92.2\nf3yfg50ga0r8n 18:24 activeblks=736  unexpiredblks=90472 expiredblks=34560 tuned_undoretention(hour)=43.9 expstealcnt=1 expblkrelcnt=1280\nf3yfg50ga0r8n 18:34 activeblks=1504 unexpiredblks=64320 expiredblks=61024 tuned_undoretention(hour)=11.4 expstealcnt=2 expblkrelcnt=14208\n374686u5v0qsh 18:44 activeblks=1120 unexpiredblks=57792 expiredblks=54752 tuned_undoretention(hour)=11.4\n374686u5v0qsh 18:54 activeblks=1888 unexpiredblks=74112 expiredblks=42784 tuned_undoretention(hour)=11.4\n374686u5v0qsh 19:04 activeblks=864  unexpiredblks=90400 expiredblks=34816 tuned_undoretention(hour)=2.   expstealcnt=1 expblkrelcnt=9216\n374686u5v0qsh 19:14 activeblks=2784 unexpiredblks=91680 expiredblks=16896 tuned_undoretention(hour)=.9\n374686u5v0qsh 19:24 activeblks=1248 unexpiredblks=94232 expiredblks=3584  tuned_undoretention(hour)=.9\n374686u5v0qsh 19:34 activeblks=1504 unexpiredblks=94816 expiredblks=4352  tuned_undoretention(hour)=.9   ssolderrcnt=1\nf3yfg50ga0r8n 19:44 activeblks=2656 unexpiredblks=93024 expiredblks=2944  tuned_undoretention(hour)=1.\n</code></pre>\n<p>The ORA-1555 occurred where the ssolderrcnt is &gt; 0 and we see the number of blocks stolen before &#8211; all expired in this case.<br />\nAll the detail about the statistics are in the V$UNDOSTAT <a href=\"https://docs.oracle.com/database/121/REFRN/GUID-39DB6CBC-AF75-4C3A-A8E1-6C923F137246.htm#REFRN30295\">documentation</a>.</p>\n<p>There is nothing more than V$UNDOSTAT here, but that query is easier if you are on command line.</p>\n",
    "protected": false
  }
}
