<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Observing Oracle</title>
	<atom:link href="https://vsadilovskiy.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://vsadilovskiy.wordpress.com</link>
	<description>Findings, solutions and other thoughts</description>
	<lastBuildDate>Wed, 28 Nov 2007 21:10:13 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<site xmlns="com-wordpress:feed-additions:1">1848988</site><cloud domain='vsadilovskiy.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>https://s0.wp.com/i/buttonw-com.png</url>
		<title>Observing Oracle</title>
		<link>https://vsadilovskiy.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="https://vsadilovskiy.wordpress.com/osd.xml" title="Observing Oracle" />
	<atom:link rel='hub' href='https://vsadilovskiy.wordpress.com/?pushpress=hub'/>
	<item>
		<title>BLOB write size and CPU</title>
		<link>https://vsadilovskiy.wordpress.com/2007/11/19/blob-write-size-and-cpu/</link>
					<comments>https://vsadilovskiy.wordpress.com/2007/11/19/blob-write-size-and-cpu/#comments</comments>
		
		<dc:creator><![CDATA[Vlad Sadilovskiy]]></dc:creator>
		<pubDate>Mon, 19 Nov 2007 07:21:23 +0000</pubDate>
				<category><![CDATA[Configuration]]></category>
		<category><![CDATA[JDBC]]></category>
		<category><![CDATA[Large Objects]]></category>
		<category><![CDATA[Troubleshooting]]></category>
		<guid isPermaLink="false">http://vsadilovskiy.wordpress.com/2007/11/19/blob-write-size-and-cpu/</guid>

					<description><![CDATA[Someone asked to help in identifying a strange problem.  The problem found to be a combination of two issues, ASSM and the BLOB loading software, that manifested as an excessive CPU utilization. In this post we should see how different write buffer size can affect write efficiency. Unfortunately, Tkprof and Statspack would often fail to point in [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Someone asked to help in identifying a strange problem.  The problem found to be a combination of two issues, <strong>ASSM</strong> and the <strong>BLOB</strong> loading software, that manifested as an <strong>excessive CPU utilization</strong>. In this post we should see how different <strong>write buffer size</strong> can affect write efficiency. <span id="more-32"></span></p>
<p>Unfortunately, <strong>Tkprof</strong> and <strong>Statspack</strong> would often fail to point in proper direction when it gets to profiling activity performed by a <a href="http://feeds.feedburner.com/~r/ObservingOracle/~3/183988682/">Call-Less Cursor</a>. In this case such cursor was responsible for writing and reading BLOBs. This issue was not specific to <strong>JDBC API</strong>. Later it was reproduced with <strong>DBMS_LOB </strong><strong>API</strong>.</p>
<p>Just as an additional point to the mentioned above topic, here is an example of Tkprof and Statspack reports from the system where this issue was reproduced with help of single threaded application in an idle environment.</p>
<p><em><strong>Tkprof</strong></em></p>
<p><code></code></p>
<blockquote><p><code>OVERALL TOTALS FOR </code><code>ALL</code><code> NON-RECURSIVE STATEMENTS</code><br />
<code></code><br />
<code>call     count       cpu    elapsed       disk      query    current        rows<br />
------- ------  -------- ---------- ---------- ---------- ----------  ----------<br />
Parse       16      0.00       0.02          0          0          0           0<br />
Execute     23      3.09       4.57          6      13894      18366          17<br />
Fetch        3      0.00       0.00          0          6          0           3<br />
------- ------  -------- ---------- ---------- ---------- ----------  ----------<br />
total       42      3.10       4.59          6      13900      18366          20</code><br />
<code></code><br />
<code>OVERALL TOTALS FOR </code><code>ALL</code><code> RECURSIVE STATEMENTS</code><br />
<code></code><br />
<code>call     count       cpu    elapsed       disk      query    current        rows<br />
------- ------  -------- ---------- ---------- ---------- ----------  ----------<br />
Parse   230212      5.39       5.14          0          0          0           0<br />
Execute 230215    176.87     173.89         47     692034     175390      176321<br />
Fetch   153422      4.22       3.96          5     230821          3       77048<br />
------- ------  -------- ---------- ---------- ---------- ----------  ----------<br />
total   613849    186.49     183.01         52     922855     175393      253369</code></p></blockquote>
<p><em><strong>Statspack</strong></em></p>
<blockquote><p><code><strong><em>Load Profile</em></strong></code><code>                            Per Second       Per Transaction</code><br />
<code>~~~~~~~~~~~~                       ---------------       ---------------</code><br />
<code>                  Redo size:          1,553,489.88        668,736,513.89</code><br />
<code>              Logical reads:            630,504.58        271,415,631.42</code><br />
<code>              Block changes:                782.47            336,833.37</code><br />
<code>             Physical reads:                171.33             73,752.42</code><br />
<code>            Physical writes:                181.92             78,311.00</code><br />
<code>                 User calls:                 42.80             18,424.58</code><br />
<code>                     Parses:                 44.40             19,114.63</code><br />
<code>                Hard parses:                  0.00                  1.00</code><br />
<code>                      Sorts:                  0.39                169.89</code><br />
<code>                     Logons:                  0.00                  0.84</code><br />
<code>                   Executes:                 44.94             19,344.89</code><br />
<code>               Transactions:                  0.00</code></p>
<p><code><em><strong>Top 5 Timed Events</strong></em>                                                    Avg %Total</code><br />
<code>~~~~~~~~~~~~~~~~~~                                                   wait   Call</code><br />
<code>Event                                            Waits    Time (s)   (ms)   Time</code><br />
<code>----------------------------------------- ------------ ----------- ------ ------</code><br />
<code>CPU time                                                     <strong>7,764</strong>          95.9</code><br />
<code>log file parallel write                         85,190         147      2    1.8</code><br />
<code>log file switch (checkpoint incomplete)            246          88    357    1.1</code><br />
<code>log file switch completion                         502          76    151     .9</code><br />
<code>control file parallel write                      7,973           9      1     .1</code><br />
<code>          -------------------------------------------------------------</code></p>
<p><code><em><strong>Instance Activity Stats</strong></em></code><br />
<code>Statistic                                      Total     per Second    per Trans</code><br />
<code>--------------------------------- ------------------ -------------- ------------</code><br />
<code>...</code><br />
<code>db block gets                          5,116,321,961      625,543.7 ############</code><br />
<code>db block gets direct                       1,442,703          176.4     75,931.7</code><br />
<code>db block gets from cache               5,114,879,258      625,367.3 ############</code><br />
<code>...</code><br />
<code>physical writes                            1,487,909          181.9     78,311.0</code><br />
<code>physical writes direct                     1,444,083          176.6     76,004.4</code><br />
<code>physical writes direct (lob)               1,442,684          176.4     75,930.7</code><br />
<code>session logical reads                  <strong>5,156,896,997</strong>      630,504.6 ############</code><br />
<code>...</code></p>
<p><code><em><strong>Segments by Logical Reads</strong></em></code><br />
<code>                                           Subobject    Obj.       Logical   Pct</code><br />
<code>Owner      Tablespace Object Name          Name         Type         Reads Total</code><br />
<code>---------- ---------- -------------------- ------------ ----- ------------ -----</code><br />
<code>SYS        SYSTEM     SEG$                              TABLE      434,992  23.6</code><br />
<code>SYS        SYSTEM     TSQ$                              TABLE      432,816  23.5</code><br />
<code><strong>TEST       TEST       SYS_LOB0000056448C00              LOB        289,808  15.7</strong></code><br />
<code>SYS        SYSTEM     I_FILE#_BLOCK#                    INDEX      288,448  15.7</code><br />
<code>SYS        SYSTEM     FILE$                             TABLE      220,416  12.0</code><br />
<code>          -------------------------------------------------------------</code></p></blockquote>
<p>As it can be seen, the number of <strong>session logical reads </strong>in the test doesn&#8217;t align well with figures in <strong>Segments by Logical Reads </strong>section. Tkprof doesn&#8217;t even have a clue about 7K CPU seconds.</p>
<p>But let&#8217;s get back to the business. What could be happening that triggered such a vast amount of reads when writing BLOBs? A call to the vendor of the software revealed that the BLOB data is written in chunks and for each chunk the BLOB was closed and reset with an updated position. So, we duplicated this behavior and have gotten following statistics using &#8220;<a href="http://asktom.oracle.com/~tkyte/runstats.html">runstats</a>&#8221; and <a href="http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:45027262935845">DbmsOutput.java</a> shared by Tom Kyte and Java API shared by R. M. Menon on <a href="http://asktom.oracle.com/" title="AskTom">AskTom</a>.</p>
<p><code>BLOB...chunk size                    32,768  32,768  32,768  32,768  32,768  32,768  32,768  32,768  32,768</code><br />
<code>BLOB...write buffer size</code><code>             2,048   4,096   8,132   8,192   16,264  16,384  24,396  <strong><font color="#339966">32,528</font></strong>  32,768</code><br />
<code>STAT</code><code>...consistent gets               971     375     119     319     51      234     27      <strong><font color="#339966">190</font></strong>     222</code><br />
<code>STAT</code><code>...consistent gets direct        252     159     52      79      16      32      </code><code>9       <strong><font color="#339966">4</font></strong>       20</code><br />
<code>STAT</code><code>...db block gets                 6,146   884     423     479     209     268     109     <strong><font color="#339966">100</font></strong>     208</code><br />
<code>STAT</code><code>...db block gets direct</code><code>          </code><code>268     140     64      76      32      44      32      <strong><font color="#339966">16      </font></strong>36</code><br />
<code>STAT</code><code>...physical reads direct (lob)</code><code>   </code><code>252     124     48      60      16      28      16      <strong><font color="#339966">0</font>       </strong>20</code><br />
<code>STAT</code><code>...physical writes direct (lob)</code><code>  </code><code>268     140     64      76      32      44      32      <strong><font color="#339966">16</font>      </strong>36</code><br />
<code>STAT</code><code>...session logical reads         7,117   1,259   542     798     260     502     136     <strong><font color="#339966">290</font>     </strong>430</code></p>
<p><code>BLOB...chunk size                    16,384  16,384  16,384  16,384  16,384  16,384  16,384  16,384  16,384</code><br />
<code>BLOB...write buffer size</code><code>             2,048   4,096   8,132   8,192   <strong><font color="#339966">16,264</font></strong>  16,384  24,396  <strong><font color="#339966">32,528</font></strong>  32,768</code><br />
<code>STAT</code><code>...consistent gets               449     222     99      213     <strong><font color="#339966">47</font>      </strong>74      25      <strong><font color="#339966">35</font>      </strong>63</code><br />
<code>STAT</code><code>...consistent gets direct        126     80      24      53      <strong><font color="#339966">8       </font></strong>22      </code><code>3       <strong><font color="#339966">8</font>       </strong>19</code><code></code><br />
<code>STAT</code><code>...db block gets                 3,904   733     397     813     <strong><font color="#339966">182</font>     </strong>295     113     <strong><font color="#339966">143</font>     </strong>250</code><br />
<code>STAT</code><code>...db block gets direct</code><code>          </code><code>142     78      32      46      <strong><font color="#339966">16</font>      </strong>30      22      <strong><font color="#339966">16</font>      </strong>26</code><br />
<code>STAT</code><code>...physical reads direct (lob)</code><code>   </code><code>126     62      16      30      <strong><font color="#339966">0</font>       </strong>14      6       <strong><font color="#339966">0</font>       </strong>10</code><br />
<code>STAT</code><code>...physical writes direct (lob)</code><code>  </code><code>142     78      32      46      <strong><font color="#339966">16</font>      </strong>30      22      <strong><font color="#339966">16</font>      </strong>26</code><br />
<code>STAT</code><code>...session logical reads         4,353   955     496     1,026   <strong><font color="#339966">229</font>     </strong>369     138     <strong><font color="#339966">178</font>     </strong>313</code></p>
<p><code>BLOB...chunk size                    8,192   8,192   8,192   8,192   8,192   8,192   8,192   8,192   8,192</code><br />
<code>BLOB...write buffer size</code><code>             2,048   4,096   <strong><font color="#339966">8,132</font></strong>   8,192   <strong><font color="#339966">16,264</font></strong>  16,384  <font color="#339966"><strong>24,396</strong>  <strong>32,528</strong></font>  32,768</code><br />
<code>STAT</code><code>...consistent gets               347     264     <strong><font color="#339966">95</font>      </strong>128     <strong><font color="#339966">71</font>      </strong>91      <strong><font color="#339966">23      17</font>      </strong>39</code><br />
<code>STAT</code><code>...consistent gets direct        63      78      <strong><font color="#339966">16</font>      </strong>35      <strong><font color="#339966">16</font>      </strong>27      <strong><font color="#339966">0       0</font>       </strong>7</code><br />
<code>STAT</code><code>...db block gets                 2,657   996     <strong><font color="#339966">349</font>     </strong>468     <strong><font color="#339966">273</font>     </strong>369     <strong><font color="#339966">103     85</font>      </strong>161</code><br />
<code>STAT</code><code>...db block gets direct</code><code>          </code><code>79      47      <strong><font color="#339966">16</font>      </strong>31      <strong><font color="#339966">16</font>      </strong>23      <strong><font color="#339966">16      16</font>      </strong>21</code><br />
<code>STAT</code><code>...physical reads direct (lob)</code><code>   </code><code>63      31      <strong><font color="#339966">0</font>       </strong>15      <strong><font color="#339966">0</font>       </strong>7       <strong><font color="#339966">0       0</font>       </strong>5</code><br />
<code>STAT</code><code>...physical writes direct (lob)</code><code>  </code><code>79      47      <strong><font color="#339966">16</font>      </strong>31      <strong><font color="#339966">16</font>      </strong>23      <strong><font color="#339966">16      16</font>      </strong>21</code><br />
<code>STAT</code><code>...session logical reads         3,004   1,260   <strong><font color="#339966">444</font>     </strong>596     <strong><font color="#339966">344</font>     </strong>460     <strong><font color="#339966">126     102</font>     </strong>200</code></p>
<p>By looking at <strong>physical reads direct (lob)</strong> statistics we can see that there are certain write buffer sizes for each BLOB chunk size that <strong>do no produce any additional reading</strong>. For our tests with chunk sizes 8K, 16K and 32K it appears that these local minimum points can be derived from <strong>BLOB chunk size</strong> and certain <strong>chunk overhead</strong> as in <strong>N*(chunk size &#8211; K)</strong>, where <strong>N</strong> is any natural number and <strong>K</strong> overhead which dependents on the chunk size as in 8K &#8211; 60 Bytes, 16K &#8211; 120 Bytes and 32K &#8211; 240 Bytes. In these points the amount of <strong>physical writes direct (lob)</strong> is minimal and what is interesting depends only on the size of the incoming data and the Block Size as in <strong>Blob Size/Block Size</strong>. From which we can see that each BLOB chunk is written only once.</p>
<p>Here is one more interesting thing to mention, although it is not confirmed. Number of additional operations in other cases exactly matches following scenario that can be clearly described as <strong>rewriting BLOB chunks</strong>, when ongoing operation reads entire <strong>BLOB chunk</strong> that is left <strong>incomplete</strong>by the previous write operation, appends data from current buffer and stores all chunk&#8217;s blocks back into the DB. This also triggers significant degradation of LIO per effective amount of written data ratio, which improves with the increase of the write buffer size. This behavior was one of the culprits of the original issue. Of course, not closing BLOB stream on each write would be a better way. However, sometime it isn&#8217;t possible to rewrite the code. If an application can be configured to use buffer of a certain length, the issue can be alleviated.</p>
<p><strong>ASSM</strong> was playing not the least role in this situation. It has known for causing process &#8220;spinning&#8221; behavior. In our case the session was sitting in the following stack.</p>
<blockquote><p><code>#0  0x000000000159fa03 in kcbgcur ()</code><br />
<code>#1  0x0000000001007f3b in ktugusc ()</code><br />
<code>#2  0x0000000001019032 in ktugti () <strong>- KTU: Kernel Transaction Undo Get Transaction table entry Information</strong></code><br />
<code>#3  0x0000000001047e66 in ktbIsItlEntryCommitted ()</code><br />
<code>#4  0x000000000104db76 in ktrIsItlEntryCommitted ()</code><br />
<code>#5  0x00000000027cfa2e in kdlxgs_init () <strong>- reclaim space from transaction freelist in index</strong></code><br />
<code>#6  0x0000000000bfab81 in ktsplbfmb ()</code><br />
<code>#7  0x0000000000bfbd80 in ktsplbrecl ()</code><br />
<code>#8  0x0000000000bd36e9 in ktspgsp_cbk1 ()</code><br />
<code>#9  0x00000000027e740f in kdlgsp_init () <strong>- Space management batching</strong></code><br />
<code>#10 0x00000000027e45cb in kdl_write1 ()</code><br />
<code>#11 0x0000000001d2ece3 in koklwrite () <strong>- KOK Lob WRITE</strong></code><br />
<code>#12 0x00000000022f2094 in kpolob () <strong>- </strong></code><code><strong>KPP</strong></code><code><strong> Lob operations</strong></code><code></code><br />
<code>#13 0x0000000000711ef8 in opiodr ()</code><br />
<code>#14 0x00000000039a973b in ttcpip ()</code><br />
<code>#15 0x000000000070df90 in opitsk ()</code><br />
<code>#16 0x0000000000710e36 in opiino ()</code><br />
<code>#17 0x0000000000711ef8 in opiodr ()</code><br />
<code>#18 0x000000000070bc23 in opidrv ()</code><br />
<code>#19 0x000000000070a0ce in sou2o ()</code><br />
<code>#20 0x00000000006d008b in opimai_real ()</code><br />
<code>#21 0x00000000006cffdc in main ()</code></p></blockquote>
<p>Moving hot BLOBs to tablespaces with <strong>manual segment space management </strong>further improved the situation.</p>
<p>Here are few papers on Metalink that could be helpful in resolving similar BLOB issues.</p>
<p>Note:<a target="_blank" href="https://metalink.oracle.com/metalink/plsql/ml2_documents.showDocument?p_database_id=NOT&amp;p_id=162345.1">162345.1</a> &#8220;LOBS &#8211; Storage, Read-consistency and Rollback&#8221;<br />
Note:<a target="_blank" href="https://metalink.oracle.com/metalink/plsql/ml2_documents.showDocument?p_database_id=NOT&amp;p_id=66431.1">66431.1</a> &#8220;LOBS &#8211; Storage, Redo and Performance Issues&#8221;<br />
Note:<a target="_blank" href="https://metalink.oracle.com/metalink/plsql/ml2_documents.showDocument?p_database_id=NOT&amp;p_id=268476.1">268476.1</a> &#8220;LOB Performance Guideline&#8221;<br />
Bug: <a target="_blank" href="https://metalink.oracle.com/metalink/plsql/ml2_documents.showFrameDocument?p_database_id=BUG&amp;p_id=5253061">5253061</a> &#8220;LOB INSERT PERFORMANCE DIFFERS AFTER INSERT DEPENDING ON COMMIT&#8221;<br />
Bug: <a target="_blank" href="https://metalink.oracle.com/metalink/plsql/ml2_documents.showFrameDocument?p_database_id=BUG&amp;p_id=6128525">6128525 </a>&#8220;ELAPSED TIME IS TOO HIGHER THAN &#8220;WAITED TIME + CPU TIME&#8221; IN ASSM LOB ACCESS&#8221;<br />
Bug: <a target="_blank" href="https://metalink.oracle.com/metalink/plsql/ml2_documents.showFrameDocument?p_database_id=BUG&amp;p_id=5131464">5131464</a> &#8220;10.1.0.4 RDBMS 10.1.0.4 SPACE PRODID-5 PORTID-226&#8221;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vsadilovskiy.wordpress.com/2007/11/19/blob-write-size-and-cpu/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">32</post-id>
		<media:content url="https://2.gravatar.com/avatar/b9e5109c7f24696d3d064bad5b582fbed3cfa2cec3570a1b526c4908099c3551?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Vlad Sadilovskiy</media:title>
		</media:content>
	</item>
		<item>
		<title>Going to OOW 2007</title>
		<link>https://vsadilovskiy.wordpress.com/2007/11/09/going-to-oow-2007/</link>
					<comments>https://vsadilovskiy.wordpress.com/2007/11/09/going-to-oow-2007/#respond</comments>
		
		<dc:creator><![CDATA[Vlad Sadilovskiy]]></dc:creator>
		<pubDate>Fri, 09 Nov 2007 20:35:15 +0000</pubDate>
				<category><![CDATA[Rants]]></category>
		<guid isPermaLink="false">http://vsadilovskiy.wordpress.com/2007/11/09/going-to-oow-2007/</guid>

					<description><![CDATA[Took entire week of PTO and I&#8217;m going to California for the first time. I&#8217;m going to Oracle Open World for the first time as well. I heard some good words about it all. I&#8217;m going there with my family too.  Tricky part is to find enough time to enjoy both &#8211; the event and the place. So, next week I probably will run [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Took entire week of PTO and I&#8217;m going to <strong>California</strong> for the first time. I&#8217;m going to <strong>Oracle Open World</strong> for the first time as well. I heard some good words about it all. I&#8217;m going there with my family too.</p>
<p> Tricky part is to find enough time to <strong>enjoy</strong> both &#8211; the event and the place. So, next week I probably will run fewer tests and help fewer customers. But I&#8217;m sure I&#8217;ll catch up later with all that new energy.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vsadilovskiy.wordpress.com/2007/11/09/going-to-oow-2007/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">30</post-id>
		<media:content url="https://2.gravatar.com/avatar/b9e5109c7f24696d3d064bad5b582fbed3cfa2cec3570a1b526c4908099c3551?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Vlad Sadilovskiy</media:title>
		</media:content>
	</item>
		<item>
		<title>Recursive Calls</title>
		<link>https://vsadilovskiy.wordpress.com/2007/11/05/recursive-calls/</link>
					<comments>https://vsadilovskiy.wordpress.com/2007/11/05/recursive-calls/#comments</comments>
		
		<dc:creator><![CDATA[Vlad Sadilovskiy]]></dc:creator>
		<pubDate>Mon, 05 Nov 2007 05:26:43 +0000</pubDate>
				<category><![CDATA[AWR]]></category>
		<category><![CDATA[Statspack]]></category>
		<category><![CDATA[Tkprof]]></category>
		<category><![CDATA[DB Tuning]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[Troubleshooting]]></category>
		<guid isPermaLink="false">http://vsadilovskiy.wordpress.com/2007/11/05/recursive-calls/</guid>

					<description><![CDATA[Here is one interesting subject &#8211; recursive calls and performance monitoring instrumentation. This is just a few observations of the session tracing facility, Statspack, AWR and Tkprof point of view on recursive calls. We want to observe and clarify how the Tkprof, Statspack and AWR calculate top and recursive call statistics. The definition of recursive call as per Metalink Note:41634.1 and [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Here is one interesting subject &#8211; <strong>recursive calls </strong>and performance monitoring <strong>instrumentation</strong>. This is just a few observations of the <strong>session tracing facility</strong>, <strong>Statspack</strong>, <strong>AWR</strong> and <strong>Tkprof</strong> point of view on recursive calls. We want to observe and clarify how the <strong>Tkprof</strong>, <strong>Statspack</strong> and <strong>AWR </strong>calculate <strong>top </strong>and <strong>recursive call statistics</strong>.<span id="more-27"></span></p>
<p>The definition of <strong>recursive call </strong>as per Metalink <a target="_blank" href="https://metalink.oracle.com/metalink/plsql/f?p=130:14:2218916324475842606::::p14_database_id,p14_docid,p14_show_header,p14_show_help,p14_black_frame,p14_font:NOT,41634.1,1,1,1,helvetica">Note:41634.1</a> and <a target="_blank" href="http://download.oracle.com/docs/cd/B19306_01/server.102/b14211/sqltrace.htm#i18112">10g Tkprof Manual</a>: </p>
<blockquote><p><em>&#8220;Recursive Calls<br />
&#8212;&#8212;&#8212;&#8212;&#8212;</em></p>
<p><em>Sometimes to execute a SQL statement issued by a user, Oracle </em><em><strong>must issue<br />
additional statements</strong>. Such statements are called <strong>&#8216;recursive calls&#8217;</strong> or<br />
<strong>&#8216;recursive SQL statements&#8217;</strong>. For example, if you insert a row into a table<br />
that does not have enough space to hold that row, Oracle makes recursive<br />
calls to allocate the space dynamically. Recursive calls are also generated<br />
when data dictionary information is not available in the data dictionary<br />
cache and must be retrieved from disk.</em></p>
<p><em>If recursive calls occur while the SQL trace facility is enabled, <strong>TKPROF</strong><br />
produces statistics for the recursive SQL statements and clearly marks them<br />
as recursive SQL statements in the output file.  Note that the </em><em><strong>statistics for<br />
a recursive SQL statement are included in the listing for that statement</strong>,<br />
<strong>not in the listing for the SQL statement that caused the recursive call</strong>.  So<br />
when you are calculating the total resources required to process a SQL<br />
statement, you should consider the statistics for that statement as well as<br />
those for recursive calls caused by that statement.&#8221;</em></p></blockquote>
<p>Recursive calls are triggered by <strong>top level calls </strong>that governs processing of statements directly issued by users (or more precisely, issued by a program that communicates directly with Oracle on behalf of its end-users or scripts). <strong>Tkprof </strong>is supposed to report <strong>base statistics</strong> (<strong>excluding</strong> the statistics of its recursive calls) of a call at any level.</p>
<p>For the purpose of the following discussion let me add the following <strong>statistics</strong> definitions taken from <a target="_blank" href="http://download.oracle.com/docs/cd/B19306_01/server.102/b14237/stats002.htm#sthref4653">Statistics Descriptions</a> that can be viewed either in Statspack or AWR report or directly using v$sysstat view:</p>
<blockquote><p><em>&#8220;<strong><u>CPU used by this session</u></strong> &#8211; Amount of <strong>CPU time</strong> (in 10s of milliseconds) <strong>used by a session</strong> <strong>from the time a</strong> <strong>user call starts until it ends</strong>. If a user call completes within 10 milliseconds, the start and end user-call time are the same for purposes of this statistics, and 0 milliseconds are added.<br />
<strong><u>recursive cpu usage</u></strong> &#8211; Total <strong>CPU time used by non-user calls</strong> (<strong>recursive calls</strong>). Subtract this value from &#8220;CPU used by this session&#8221; to determine how much CPU time was used by the user calls.&#8221;</em></p></blockquote>
<p>Documentation says that &#8220;CPU used by this session&#8221; statistics includes CPU used by recursive calls.</p>
<p>Let&#8217;s run a test and take a look at this from practical perspecive and see how well 10.2.0.3 DB conforms to its documentation. I&#8217;ve chosen following code for this testing:</p>
<blockquote><p><code>create or replace function recursive_function(leveln number, maxlevel number) return number</code><br />
<code>as</code><br />
<code>    l_level number := leveln;</code><br />
<code>    c number := 0;</code><br />
<code>begin</code><br />
<code></code><br />
<code>    loop</code><br />
<code>        exit when c &gt; 4000000000;</code><br />
<code>        c := c + 1;</code><br />
<code>    end loop;</code><br />
<code></code><br />
<code>    if l_level+1 &lt;= maxlevel then</code><br />
<code>        execute immediate 'select /*+ query at level '||(l_level+1)||' */ recursive_function('||(l_level+1)||','||maxlevel||') from dual' into c;</code><br />
<code>    end if;</code><br />
<code>    </code><br />
<code>    return c;</code><br />
<code>end;</code><br />
<code>/</code><br />
<code></code><br />
<code>begin </code><br />
<code>    perfstat.statspack.snap(i_ucomment=&gt;'start at '||to_char(sysdate,'yy/mm/dd hh24:mi:ss'));</code><br />
<code>    DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT ('</code><code>ALL</code><code>');</code><br />
<code>end;</code><br />
<code>/</code><br />
<code></code><br />
<code>alter session set events '10046 trace name context forever, level 8';               </code><br />
<code></code><br />
<code>select /*+ top */ recursive_function(0,3) from dual;</code><br />
<code></code><br />
<code>begin </code><br />
<code>    perfstat.statspack.snap(i_ucomment=&gt;'end at '||to_char(sysdate,'yy/mm/dd hh24:mi:ss'));</code><br />
<code>    DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT ('</code><code>ALL</code><code>');</code><br />
<code>end;</code><br />
<code>/</code><br />
<code></code><br />
<code>alter session set events '10046 trace name context off';</code></p></blockquote>
<p>It triggers chain of recursive calls with max level 3. This code generates quasi-equal amount of pure CPU load and should allow identifying resource consumption on any level quite easily.</p>
<p><strong><em>Raw Trace:</em></strong></p>
<blockquote><p><code>PARSING IN CURSOR #53 len=51 dep=0 uid=57 oct=3 lid=57 tim=1166023881658166 hv=1409094977 ad='6cf1aba8'</code><br />
<code>select /*+ top */ recursive_function(0,3) from dual</code><br />
<code>END OF STMT</code><br />
<code>PARSE #53:c=0,e=163,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=1166023881658162</code><br />
<code>EXEC #53:c=0,e=37,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=1166023881658276</code><br />
<code>WAIT #53: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=56115 tim=1166023881658319</code><br />
<code>WAIT #53: nam='SQL*Net message from client' ela= 44597 driver id=1413697536 #bytes=1 p3=0 obj#=56115 tim=1166023881702983</code><br />
<code>*** 2007-11-02 09:05:46.334</code><br />
<code>=====================</code><br />
<code>PARSING IN CURSOR #13 len=64 dep=1 uid=57 oct=3 lid=57 tim=1166024166342227 hv=1557986045 ad='72a95828'</code><br />
<code>select /*+ query at level 1 */ recursive_function(1,3) from dual</code><br />
<code>END OF STMT</code><br />
<code>PARSE #13:c=2999,e=2789,p=0,cr=0,cu=0,mis=1,r=0,dep=1,og=1,tim=1166024166342221</code><br />
<code>EXEC #13:c=0,e=37,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=1,tim=1166024166342394</code><br />
<code>*** 2007-11-02 09:10:59.564</code><br />
<code>=====================</code><br />
<code>PARSING IN CURSOR #55 len=64 dep=2 uid=57 oct=3 lid=57 tim=1166024472231315 hv=4273745374 ad='6e06c2e8'</code><br />
<code>select /*+ query at level 2 */ recursive_function(2,3) from dual</code><br />
<code>END OF STMT</code><br />
<code>PARSE #55:c=3000,e=2617,p=0,cr=0,cu=0,mis=1,r=0,dep=2,og=1,tim=1166024472231309</code><br />
<code>EXEC #55:c=0,e=38,p=0,cr=0,cu=0,mis=0,r=0,dep=2,og=1,tim=1166024472231491</code><br />
<code>*** 2007-11-02 09:15:50.950</code><br />
<code>=====================</code><br />
<code>PARSING IN CURSOR #14 len=64 dep=3 uid=57 oct=3 lid=57 tim=1166024756787955 hv=1817767248 ad='6e2b2ec8'</code><br />
<code>select /*+ query at level 3 */ recursive_function(3,3) from dual</code><br />
<code>END OF STMT</code><br />
<code>PARSE #14:c=2000,e=2633,p=0,cr=0,cu=0,mis=1,r=0,dep=3,og=1,tim=1166024756787948</code><br />
<code>EXEC #14:c=0,e=65,p=0,cr=0,cu=0,mis=0,r=0,dep=3,og=1,tim=1166024756788155</code><br />
<code>*** 2007-11-02 09:20:42.250</code><br />
<code>FETCH #14:<strong>c=291241724</strong>,<strong>e=284472442</strong>,p=0,cr=0,cu=0,mis=0,r=1,<strong>dep=3</strong>,og=1,tim=1166025041260627</code><br />
<code>STAT</code><code>#14 id=1 cnt=1 pid=0 pos=1 obj=0 op='</code><code>FAST</code><code>DUAL  (cr=0 pr=0 pw=0 time=5 us)'</code><br />
<code>FETCH #55:<strong>c=582567435</strong>,<strong>e=569029386</strong>,p=0,cr=0,cu=0,mis=0,r=1,<strong>dep=2</strong>,og=1,tim=1166025041260907</code><br />
<code>STAT</code><code>#55 id=1 cnt=1 pid=0 pos=1 obj=0 op='</code><code>FAST</code><code>DUAL  (cr=0 pr=0 pw=0 time=3 us)'</code><br />
<code>FETCH #13:<strong>c=895731828</strong>,<strong>e=874918635</strong>,p=0,cr=0,cu=0,mis=0,r=1,<strong>dep=1</strong>,og=1,tim=1166025041261058</code><br />
<code>WAIT #53: nam='SQL*Net message to client' ela= 4 driver id=1413697536 #bytes=1 p3=0 obj#=56115 tim=1166025041261123</code><br />
<code>FETCH #53:<strong>c=1187120530</strong>,<strong>e=1159558108</strong>,p=0,cr=0,cu=0,mis=0,r=1,<strong>dep=0</strong>,og=1,tim=1166025041261160</code><br />
<code>WAIT #53: nam='SQL*Net message from client' ela= 54812 driver id=1413697536 #bytes=1 p3=0 obj#=56115 tim=1166025041316063</code><br />
<code>STAT</code><code>#53 id=1 cnt=1 pid=0 pos=1 obj=0 op='</code><code>FAST</code><code>DUAL  (cr=0 pr=0 pw=0 time=5 us)'</code></p></blockquote>
<p>In the 10g raw trace time is given in microseconds. So, you see how the CPU cosumption and elapsed time are reported in the trace. At each level reported as its own CPU load plus the CPU load from the call sub-tree (all descendants):</p>
<blockquote><p><code>CPU<sub>L3</sub> (291241724)  = CPU<sub>L3.base</sub> + CPU<sub>L4</sub>(0: there are no further descendants)</code><br />
<code>CPU<sub>L2</sub> (582567435)  = CPU<sub>L2.base</sub> + CPU<sub>L3</sub>(291241724)</code><br />
<code>CPU<sub>L1</sub> (895731828)  = CPU<sub>L1.base</sub> + CPU<sub>L2</sub>(582567435)</code><br />
<code>CPU<sub>L0</sub> (1187120530) = CPU<sub>L0.base</sub> + CPU<sub>L1</sub>(895731828)</code></p>
<p>or,</p>
<p><code>CPU<sub>L3.base</sub> = CPU<sub>L3</sub> = 291241724 = 291 s</code><br />
<code>CPU<sub>L2.base</sub> = CPU<sub>L2</sub> (582567435) - CPU<sub>L3</sub>(291241724) = 291325711 = 291 s</code><br />
<code>CPU<sub>L1.base</sub> = CPU<sub>L1</sub> (895731828) - CPU<sub>L2</sub>(582567435) = 313164393 = 313 s</code><br />
<code>CPU<sub>L0.base</sub> = CPU<sub>L0</sub> (1187120530) - CPU<sub>L1</sub>(895731828) = 291388702 = 291 s</code></p></blockquote>
<p><strong><em>Tkprof:</em></strong></p>
<blockquote><p><code>select /*+ top */ recursive_function(0,3)</code><br />
<code>from</code><br />
<code> dual</code><br />
<code></code><br />
<code>call     count       cpu    elapsed       disk      query    current        rows</code><br />
<code>------- ------  -------- ---------- ---------- ---------- ----------  ----------</code><br />
<code>Parse        1      0.00       0.00          0          0          0           0</code><br />
<code>Execute      1      0.00       0.00          0          0          0           0</code><br />
<code>Fetch        1   1187.12    1159.55          0          0          0           1</code><br />
<code>------- ------  -------- ---------- ---------- ---------- ----------  ----------</code><br />
<code>total        3   <strong>1187.12</strong>    <strong>1159.55</strong>          0          0          0           1</code><br />
<code></code><br />
<code>Parsing user id: 57</code><br />
<code></code><br />
<code>================================================================================</code><br />
<code>select /*+ query at level 1 */ recursive_function(1,3)</code><br />
<code>from</code><br />
<code> dual</code><code></code><br />
<code></code><br />
<code>call     count       cpu    elapsed       disk      query    current        rows</code><br />
<code>------- ------  -------- ---------- ---------- ---------- ----------  ----------</code><br />
<code>Parse        1      0.00       0.00          0          0          0           0</code><br />
<code>Execute      1      0.00       0.00          0          0          0           0</code><br />
<code>Fetch        1    313.16     305.88          0          0          0           1</code><br />
<code>------- ------  -------- ---------- ---------- ---------- ----------  ----------</code><br />
<code>total        3    <strong>313.16</strong>     <strong>305.88</strong>          0          0          0           1</code><br />
<code></code><br />
<code>Parsing user id: 57     (<strong>recursive depth: 1</strong>)</code><br />
<code></code><br />
<code>================================================================================</code><br />
<code>select /*+ query at level 2 */ recursive_function(2,3)</code><br />
<code>from</code><br />
<code> dual</code><code></code><br />
<code></code><br />
<code>call     count       cpu    elapsed       disk      query    current        rows</code><br />
<code>------- ------  -------- ---------- ---------- ---------- ----------  ----------</code><br />
<code>Parse        1      0.00       0.00          0          0          0           0</code><br />
<code>Execute      1      0.00       0.00          0          0          0           0</code><br />
<code>Fetch        1    291.32     284.55          0          0          0           1</code><br />
<code>------- ------  -------- ---------- ---------- ---------- ----------  ----------</code><br />
<code>total        3    <strong>291.32</strong>     <strong>284.55</strong>          0          0          0           1</code><br />
<code></code><br />
<code>Parsing user id: 57     (<strong>recursive depth: 2</strong>)</code><br />
<code></code><br />
<code>================================================================================</code><br />
<code>select /*+ query at level 3 */ recursive_function(3,3)</code><br />
<code>from</code><br />
<code> dual</code><br />
<code></code><br />
<code></code><br />
<code>call     count       cpu    elapsed       disk      query    current        rows</code><br />
<code>------- ------  -------- ---------- ---------- ---------- ----------  ----------</code><br />
<code>Parse        1      0.00       0.00          0          0          0           0</code><br />
<code>Execute      1      0.00       0.00          0          0          0           0</code><br />
<code>Fetch        1    291.24     284.47          0          0          0           1</code><br />
<code>------- ------  -------- ---------- ---------- ---------- ----------  ----------</code><br />
<code>total        3    <strong>291.24</strong>     <strong>284.47</strong>          0          0          0           1</code><br />
<code></code><br />
<code>Parsing user id: 57     (<strong>recursive depth: 3</strong>)</code></p></blockquote>
<p>I always thought Tkprof doesn&#8217;t report <strong>net statistics </strong>for calls, but now I see how wrong I was. From this test it is obvious that the Tkprof reported base times for recursive calls at all levels, and <strong>only</strong> for the <strong>top level calls</strong> the <strong>CPU</strong> and <strong>elapsed time</strong> are defined as <strong>gross load</strong> including all levels: CPU<sub>L0</sub> = CPU<sub>L0.base</sub> + CPU<sub>L1.base</sub> + CPU<sub>L2.base</sub> + CPU<sub>L3.base </sub> = 291 + 313 + 291 + 291 = 1187 s. My memory might be playing tricks with me, but I recall I saw a discussion on Jonathan Lewis&#8217;s blog about this Tkprof deficiency. Maybe someone will update me where it was.</p>
<p><strong><em>AWR:</em></strong></p>
<blockquote><p><code><strong><em>SQL ordered by Elapsed Time</em></strong></code><br />
<code></code><br />
<code>  Elapsed      CPU                  Elap per  % Total</code><br />
<code>  Time (s)   Time (s)  Executions   Exec (s)  DB Time    SQL Id</code><br />
<code>---------- ---------- ------------ ---------- ------- -------------</code><br />
<code>     <strong>1,160</strong>      <strong>1,160</strong>            1     1159.6    99.8 1rcptud9zu5a1</code><br />
<code>Module: SQL Developer</code><br />
<code>select /*+ top */ recursive_function(0,3) from dual</code><br />
<code></code><br />
<code>       <strong>875</strong>        <strong>875</strong>            1      874.9    75.3 9pgc4u1fdtyrx</code><br />
<code>Module: SQL Developer</code><br />
<code>select /*+ query at level 1 */ recursive_function(1,3) from dual</code><br />
<code></code><br />
<code>       <strong>569</strong>        <strong>569</strong>            1      569.0    49.0 0v0qmk7zbsbfy</code><br />
<code>Module: SQL Developer</code><br />
<code>select /*+ query at level 2 */ recursive_function(2,3) from dual</code><br />
<code></code><br />
<code>       <strong>284</strong>        <strong>284</strong>            1      284.5    24.5 2zfr66tq5jvah</code><br />
<code>Module: SQL Developer</code><br />
<code>select /*+ query at level 3 */ recursive_function(3,3) from dual</code><br />
<code><br />
</code><br />
<code><strong><em>Top 5 Timed Events</em></strong>                                         Avg %Total</code><br />
<code>~~~~~~~~~~~~~~~~~~                                        wait   Call</code><br />
<code>Event                                 Waits    Time (s)   (ms)   Time Wait Class</code><br />
<code>------------------------------ ------------ ----------- ------ ------ ----------</code><br />
<code>CPU time                                          <strong>1,162</strong>         100.0</code><br />
<code>control file parallel write             396           1      1    0.0 System I/O</code><br />
<code>...</code><br />
<code></code><br />
<code></code><br />
<code><strong><em>Time Model Statistics</em></strong></code><br />
<code></code><br />
<code>Statistic Name                                       Time (s) % of DB Time</code><br />
<code>------------------------------------------ ------------------ ------------</code><br />
<code>sql execute elapsed time                              <strong>1,162.0</strong>        100.0</code><br />
<code>DB CPU                                                <strong>1,161.9</strong>        100.0</code><br />
<code>PL/SQL execution elapsed time                         <strong>1,159.6</strong>         99.8</code><br />
<code>...</code><br />
<code>DB time                                               <strong>1,162.1</strong>          N/A</code><br />
<code>background elapsed time                                   2.9          N/A</code><br />
<code>background cpu time                                       1.5          N/A</code><br />
<code></code><br />
<code></code><br />
<strong><code><em>Instance Activity Stats</em></code><br />
<code></code></strong><br />
<code>Statistic                                     Total     per Second     per Trans</code><br />
<code>-------------------------------- ------------------ -------------- -------------</code><br />
<code>CPU used by this session                    <strong>118,971</strong>          100.0      13,219.0</code><br />
<code>CPU used when call started                  <strong>118,946</strong>           99.9      13,216.2</code><br />
<code>recursive cpu usage                          <strong>89,804</strong>           75.5       9,978.2</code></p></blockquote>
<p>I rearranged it a little bit for better view.  </p>
<p>First of all, the top section shows that each of the times reported at each level contain times of its descendants (i.e. as in raw trace). Well, no wonder, there is probably not enough information to track call dependency and subtract statistics of children from a parent. Anyhow, it reports <strong>gross load</strong> for each <strong>recursive level</strong> and <strong>top level calls</strong>. Anyone analyzing AWR reports should note statement <em>&#8220;Resources reported for PL/SQL code includes the resources used by all SQL statements called by the code.&#8221;</em>that precedes this section. Apparently it is actually true not only for PL/SQL code, but for <strong>any type</strong> of code. This can be seen in the time model statistics where the <strong>sql execute elapsed</strong> time roughly equal <strong>PL/SQL execution elapsed time</strong>.</p>
<p>Also, comparing this section to the raw trace or Tkprof output shows that in the AWR report <strong>CPU time matches</strong> exactly the <strong>elapsed time</strong>, although it was not the same in the raw trace. This would seem just a reporting &#8220;feature&#8221;, if not for the information from the further sections. CPU time in <strong>Top 5 Timed Events</strong> and DB CPU in <strong>Time Model Statistics</strong> is roughly about 1,160 s. Ignoring small difference, same time is spent by the top level statement. Only <strong>Instance Activity Stats </strong>section shows 1,189.7 s that almost matches the raw trace CPU time consumed by all subject statements with a little offset of 2.58 s. Further, the <strong>recursive cpu usage </strong>of 898 s matches the CPU time of the recursive calls starting at level 1 with difference of 2.3 s. Both deltas for the most part are time spent in Statspack subroutines that were captured by AWR.</p>
<p><strong><em>Statspack:</em></strong></p>
<blockquote><p><code><strong><em>Top 5 Timed Events</em></strong>                                                    Avg %Total</code><br />
<code>~~~~~~~~~~~~~~~~~~                                                   wait   Call</code><br />
<code>Event                                            Waits    Time (s)   (ms)   Time</code><br />
<code>----------------------------------------- ------------ ----------- ------ ------</code><br />
<code>CPU time                                                     <strong>1,190</strong>          99.9</code><br />
<code>control file parallel write                        397           1      1     .0</code><br />
<code>...</code></p></blockquote>
<p>In Statspack the Time Model Statistics and Instance Activity Stats precisely equal to the corresponding sections in the AWR report. The SQL statistics wasn&#8217;t captured for our statements because they didn&#8217;t generate logical or physical reads nor they generate other activity that is considered a treat by the Statspack. However in the <strong>Top 5 Timed Events </strong>you can see that the <strong>CPU time </strong>is the figure of <strong>CPU used by this session </strong>statistics in the <strong>Instance Activity Stats, </strong>so it comes from <strong>v$sysstat </strong>view.</p>
<p>This behavior is different from AWR algorithm, which rather seem to be taking CPU time in Top 5 Timed Events from <strong>v$sys_time_model </strong>or directly from their common source. In case v$sys_time_model and v$sysstat have different source of information, AWR is not bound to the figures of the later when reporting Top 5 Timed Events. This perhaps holds an explanation for the <a href="http://jonathanlewis.wordpress.com/2007/11/01/awr-oddity/">AWR oddity</a> seen by Jonathan Lewis. It would be interesting to find the relevant clues in the reports or in this particular system.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vsadilovskiy.wordpress.com/2007/11/05/recursive-calls/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">27</post-id>
		<media:content url="https://2.gravatar.com/avatar/b9e5109c7f24696d3d064bad5b582fbed3cfa2cec3570a1b526c4908099c3551?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Vlad Sadilovskiy</media:title>
		</media:content>
	</item>
		<item>
		<title>Call-Less Cursor</title>
		<link>https://vsadilovskiy.wordpress.com/2007/10/29/trace-and-statspack-lob-1/</link>
					<comments>https://vsadilovskiy.wordpress.com/2007/10/29/trace-and-statspack-lob-1/#comments</comments>
		
		<dc:creator><![CDATA[Vlad Sadilovskiy]]></dc:creator>
		<pubDate>Mon, 29 Oct 2007 19:29:30 +0000</pubDate>
				<category><![CDATA[DB Tuning]]></category>
		<category><![CDATA[Large Objects]]></category>
		<category><![CDATA[Statspack]]></category>
		<category><![CDATA[Tkprof]]></category>
		<category><![CDATA[Troubleshooting]]></category>
		<category><![CDATA[trace]]></category>
		<guid isPermaLink="false">http://vsadilovskiy.wordpress.com/2007/10/29/trace-and-statspack-lob-1/</guid>

					<description><![CDATA[Many people know that the Tkprof does not report base statistics and times for calls that have recursive calls. This can be handled by other alternative tools. There is one more unfortunate effect to watch out for when doing tuning of a DB that does fair amount of LOB operations. It seems to be more fundamental and much harder to cope with. Someone was trying [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Many people know that the <strong>Tkprof</strong> does not report <strong>base</strong> <strong>statistics </strong>and <strong>times</strong> for calls that have <strong>recursive calls</strong>. This can be handled by other alternative tools. There is one more unfortunate effect to watch out for when doing tuning of a DB that does fair amount of <strong>LOB</strong> operations. It seems to be more fundamental and much harder to cope with.<span id="more-26"></span></p>
<p>Someone was trying to capture performance problem for BLOB loading application. Any method they tried didn&#8217;t show good clue to the problem, and they could wonder around it for longer time unless weren&#8217;t hinted on certain LOB handling patterns that had been known for some buggy behavior.</p>
<p>But this was just an issue that made me post this other related observation. Here are two excerpts from <strong>Tkprof </strong>and <strong>Statspack</strong> reports from database where the case was reproduced.<br />
<strong><em> </em></strong></p>
<p><strong><em>Tkprof</em></strong></p>
<blockquote><p><code></code><br />
<code>OVERALL TOTALS FOR <code>ALL</code><code> NON-RECURSIVE STATEMENTS</code><br />
<code></code><br />
<code>call     count       cpu    elapsed       disk      query    current        rows</code><br />
<code>------- ------  -------- ---------- ---------- ---------- ----------  ----------</code><br />
<code>Parse        7      0.02       0.02          4         86          0           0</code><br />
<code>Execute      9      0.66       1.14         82       2956       5618           8</code><br />
<code>Fetch        1      0.00       0.00          0          2          0           1</code><br />
<code>------- ------  -------- ---------- ---------- ---------- ----------  ----------</code><br />
<code>total       17      0.68       1.16         86       3044       5618           9</code><br />
<code></code><br />
<code>Elapsed times include waiting on following events:</code><br />
<code>  Event waited on                             Times   Max. Wait  Total Waited</code><br />
<code>  ----------------------------------------   Waited  ----------  ------------</code><br />
<code>  SQL*Net message from client                100014       54.07        112.26</code><br />
<code>  db file sequential read                         1        0.00          0.00</code><br />
<code>  SQL*Net message to client                  100013        0.00          0.19</code><br />
<code>  log file sync                                  10        0.00          0.02</code><br />
<code>  latch: shared pool                             11        0.02          0.02</code><br />
<code></code><br />
<code></code><br />
<code>OVERALL TOTALS FOR </code><code>ALL</code><code> RECURSIVE STATEMENTS</code><br />
<code></code><br />
<code>call     count       cpu    elapsed       disk      query    current        rows</code><br />
<code>------- ------  -------- ---------- ---------- ---------- ----------  ----------</code><br />
<code>Parse     4644      0.94       0.93          0          0        107           0</code><br />
<code>Execute  11059      6.06       9.85        570      45295       5516        8933</code><br />
<code>Fetch    23131      0.70       2.23        305      38484          3       28673</code><br />
<code>------- ------  -------- ---------- ---------- ---------- ----------  ----------</code><br />
<code>total    38834      7.71      13.03        875      83779       5626       37606</code><br />
<code></code><br />
<code>Elapsed times include waiting on following events:</code><br />
<code>  Event waited on                             Times   Max. Wait  Total Waited</code><br />
<code>  ----------------------------------------   Waited  ----------  ------------</code><br />
<code>  db file sequential read                    113211        0.30        324.45</code><br />
<code>  control file sequential read                  855        0.03          0.06</code><br />
<code>  direct path write                          154743        0.00          0.70</code><br />
<code>  direct path read                            99973        0.00          0.64</code><br />
<code>  log file switch completion                    111        0.97         65.21</code><br />
<code>  log file switch (checkpoint incomplete)       255        0.97        119.11</code><br />
<code>  latch: shared pool                              4        0.00          0.00</code><br />
<code>  latch: checkpoint queue latch                   1        0.00          0.00</code><br />
<code>  latch: library cache                            1        0.00          0.00</code><br />
<code>  latch: cache buffers chains                     1        0.00          0.00</code><br />
<code>  db file scattered read                          1        0.00          0.00</code></code></p></blockquote>
<p><strong><em>Statspack</em></strong></p>
<blockquote><p><code></code><br />
<code>  </code><code><code>Top 5 Timed Events                                                    Avg %Total</code><br />
<code>~~~~~~~~~~~~~~~~~~                                                   wait   Call</code><br />
<code>Event                                            Waits    Time (s)   (ms)   Time</code><br />
<code>----------------------------------------- ------------ ----------- ------ ------</code><br />
<code>db file sequential read                        121,368         373      3   49.4</code><br />
<code>CPU time                                                       141          18.7</code><br />
<code>log file switch (checkpoint incomplete)            263         122    463   16.1</code><br />
<code>log file switch completion                         113          66    586    8.8</code><br />
<code>log file parallel write                          3,837          47     12    6.3</code><br />
<code>          -------------------------------------------------------------</code><br />
<code></code><br />
<code>Time Model System Stats  DB/Inst: TST10203/tst10203  Snaps: 2625-2631</code><br />
<code>-&gt; Ordered by % of DB time desc, Statistic name</code><br />
<code></code><br />
<code>Statistic                                       Time (s) % of DB time</code><br />
<code>----------------------------------- -------------------- ------------</code><br />
<code>DB CPU                                             292.3         40.1</code><br />
<code>sql execute elapsed time                            45.8          6.3</code><br />
<code>PL/SQL execution elapsed time                       32.8          4.5</code><br />
<code>parse time elapsed                                   5.4           .7</code><br />
<code>hard parse elapsed time                              5.3           .7</code><br />
<code>PL/SQL compilation elapsed time                      0.1           .0</code><br />
<code>hard parse (sharing criteria) elaps                  0.1           .0</code><br />
<code>connection management call elapsed                   0.0           .0</code><br />
<code>repeated bind elapsed time                           0.0           .0</code><br />
<code>hard parse (bind mismatch) elapsed                   0.0           .0</code><br />
<code>sequence load elapsed time                           0.0           .0</code><br />
<code>DB time                                            728.5</code><br />
<code>background elapsed time                            130.7</code><br />
<code>background cpu time                                 27.5</code><br />
<code>          -------------------------------------------------------------</code><br />
<code></code><br />
</code></p></blockquote>
<p>Both parts indicate that there was serious activity, like waits on the sequential disk reading and redo log synchronization, CPU utilization, that was not reported in category &#8220;sql execute elapsed time&#8221; and &#8220;PL/SQL execution elapsed time&#8221;. There was no statement reported in <strong>Tkprof</strong> or <strong>Statspack</strong> that generated this activity, but there was a particular cursor seen all over the <strong>10046 trace</strong> that was responsible for some of these missing components.</p>
<p>I kind of was lucky to see it, because <strong>the cursor</strong> has <strong>no associated</strong> <strong>calls </strong>whatsoever, only <strong>wait </strong>records. Unless there are waits associated with such cursor, there will be no records about it in the Oracle Trace. Another &#8220;funny&#8221; thing is that this <strong>call-less</strong> cursor can have <strong>recursive calls</strong> too. This cursor is created solely to write and read LOB content.</p>
<p>So, here are few words of caution for those who do performance troubleshooting using raw trace files, Statspack or <span>ASH/AWR reports. Tkprof or other tools that would try to calculate CPU, Elapsed Time or Wait statistics and build <strong>hierarchy of calls</strong> of sessions containing </span><strong>LOB operations</strong> will likely produce incorrect results from slightly wrong to misleading. This is because calls contain major information that allows traversing <strong>call hierarchy</strong> and calculating <strong>base statistics</strong> and <strong>timing</strong> figures. The &#8220;missing&#8221; calls might cause whole call hierarchy tree to break. For the same reason <strong>Statspack </strong>reports may show resource consumption without any visible <strong>consumer</strong>.</p>
<p>One more thing worth mentioning. If LOB operations are <strong>wrapped</strong> into code that uses <strong>calls </strong>to communicate with the database (i.e. PL/SQL anonymous blocks or procedures), then the resources consumed by the LOB operations inside that code will be assigned to these <strong>calls</strong>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vsadilovskiy.wordpress.com/2007/10/29/trace-and-statspack-lob-1/feed/</wfw:commentRss>
			<slash:comments>11</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">26</post-id>
		<media:content url="https://2.gravatar.com/avatar/b9e5109c7f24696d3d064bad5b582fbed3cfa2cec3570a1b526c4908099c3551?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Vlad Sadilovskiy</media:title>
		</media:content>
	</item>
		<item>
		<title>Tuning Collections in Queries [1]</title>
		<link>https://vsadilovskiy.wordpress.com/2007/10/25/tuning-collections-in-queries-1/</link>
					<comments>https://vsadilovskiy.wordpress.com/2007/10/25/tuning-collections-in-queries-1/#comments</comments>
		
		<dc:creator><![CDATA[Vlad Sadilovskiy]]></dc:creator>
		<pubDate>Thu, 25 Oct 2007 13:40:56 +0000</pubDate>
				<category><![CDATA[Collections]]></category>
		<category><![CDATA[SQL Tuning]]></category>
		<category><![CDATA[Troubleshooting]]></category>
		<category><![CDATA[CBO]]></category>
		<category><![CDATA[SQL tuning]]></category>
		<guid isPermaLink="false">http://vsadilovskiy.wordpress.com/2007/10/25/tuning-collections-in-queries-1/</guid>

					<description><![CDATA[[To Introduction]  I will continue series about tuning collections in queries starting from the simplest case – collection of values joined to one table. Our subject SQL statements look similar to the following two forms. 1) select table1.*   from table1  where table1.f1 in        (select column_value from table(test_statement.getList1) nlist1); and 2) select table1.*   [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>[<a href="https://vsadilovskiy.wordpress.com/2007/10/09/substituting-collections-for-in-list/"><font color="#0000ff">To Introduction</font></a>] </p>
<p>I will continue series about tuning collections in queries starting from the simplest case – <strong>collection of values joined to one table</strong>. Our subject SQL statements look similar to the following two forms.<span id="more-9"></span></p>
<blockquote><p><code>1)<br />
select table1.*<br />
  from table1<br />
 where table1.f1 in<br />
       (select column_value from table(test_statement.getList1) nlist1);</code></p></blockquote>
<p>and</p>
<blockquote><p><code>2)<br />
select table1.*<br />
  from table1, table(test_statement.getList1) nlist1<br />
 where t1.object_id = nlist1.column_value;</code></p></blockquote>
<p>We will run them in several ways by adding hints and CBO parameters. First test run is dedicated to show default CBO computations. Note cryptic name <strong>KOKBF$</strong> in the predicate section of the explain plan. KOKBF$ is a generic alias given the table expressions. <strong>COLLECTION ITERATOR PICKLER FETCH</strong> is an operation that retrieves values from collections (if collection was instantiated in the query the operation will read: <strong>COLLECTION ITERATOR CONSTRUCTOR FETCH</strong>).</p>
<p><strong><em>Test 1.1:</em></strong></p>
<blockquote><p><code>select /*+ gather_plan_statistics */        t1.object_name,t1.object_type   from t1</code><br />
<code>where t1.object_id in        (select *           from table(cast(test_statement.getList1 as table_of_number)) nlist1)</code><br />
<code></code><br />
<code>Plan:</code><br />
<code></code><br />
<code>----------------------------------------------------------------------------------------------------------------------------</code><br />
<code>| Id  | Operation                           | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |</code><br />
<code>----------------------------------------------------------------------------------------------------------------------------</code><br />
<code>|   1 |  <strong>NESTED LOOPS</strong>                       |          |      1 |    <strong>255</strong> |   <strong>1252K</strong>|00:02:07.32 |    5091K|    177K|   2959 |</code><br />
<code>|   2 |   </code><code>SORT</code><code> UNIQUE                       |          |      1 |    <strong><font color="#0000ff">255</font></strong> |   <strong>1878K</strong>|00:00:31.30 |      31 |   2959 |   2959 |</code><br />
<code>|   3 |    COLLECTION ITERATOR PICKLER FETCH| GETLIST1 |      1 |        |   2000K|00:00:04.28 |       0 |      0 |      0 |</code><br />
<code>|   4 |   TABLE ACCESS BY INDEX ROWID       | T1       |   1878K|      1 |   1252K|00:01:31.73 |    5091K|    174K|      0 |</code><br />
<code>|*  5 |    <strong>INDEX UNIQUE SCAN</strong>                | T1_I     |   1878K|      1 |   1252K|00:00:37.04 |    3839K|  28328 |      0 |</code><br />
<code>----------------------------------------------------------------------------------------------------------------------------</code><br />
<code></code><br />
<code>Predicate Information (identified by operation id):</code><br />
<code>---------------------------------------------------</code><br />
<code></code><br />
<code>   5 - access("T1"."OBJECT_ID"=VALUE(KOKBF$))</code></p></blockquote>
<p>About two minute runtime is not completely bad. But let’s see what we are driving into here. <strong>Nested Loops</strong> and <strong>Index Access</strong> isn’t very good choice for getting &gt; 10% of the data of the base table. Clearly, the estimated cardinality in bold is the culprit here. The value in row with Id 2 is not the part of the output, rather it was taken from CBO trace figures. The original <strong>10053 trace</strong> file doesn’t have definite clue where this figure comes from. For the reason described below, this could be a function of the default block size.</p>
<blockquote><p><code>BASE STATISTICAL INFORMATION</code><br />
<code>***********************</code><br />
<code>Table Stats::</code><br />
<code>  Table: KOKBF$  Alias: KOKBF$  (<strong>NOT ANALYZED</strong>)</code><br />
<code>    <strong>#Rows: 8168</strong>  <strong>#Blks:  100  AvgRowLen:  100.00</strong></code><code></code><br />
<code></code><br />
<code>...</code><br />
<code>Join order[2]:  KOKBF$[KOKBF$]#1  T1[T1]#0</code><br />
<code>    </code><code>SORT</code><code> resource      Sort statistics</code><br />
<code>      Sort width:         459 Area size:      402432 Max Area size:    80530432</code><br />
<code>      Degree:               1</code><br />
<code>      Blocks to Sort:    2865 Row size:           13 Total Rows:        1800000</code><br />
<code>      Initial runs:         2 Merge passes:        1 IO Cost / pass:       1554</code><br />
<code>      Total IO sort cost: 4419      Total CPU sort cost: 1764307007</code><br />
<code>      Total Temp space used: 28894000</code><br />
<code>***************</code><br />
<code>Now joining: T1[T1]#0</code><br />
<code>***************</code><br />
<code>NL Join</code><br />
<code>  Outer table: Card: <strong>255.25</strong>  Cost: 4653.33  Resp: 4653.33  Degree: 1  Bytes: 2</code><code></code></p></blockquote>
<p>The outer table KOKBF$ was assigned <strong>default cardinality</strong> as <strong>num_of_blocks * (block_size &#8211; cache_layer) / avg_row_len</strong>. In all tests cache_layer is 24. Something tells me it is similar to the 24 bytes per INITRANS, but I still cannot get my head around the fact where the block fixed header size has gone. It might be something else though. Anyway, given the figures, our default cardinality is <strong>100 * (8192 – 24) / 100 = 8168</strong>. With 16K block this would equal 16360 etc. When the collection is uniquely sorted for “IN” clause, its computed cardinality is reduced to 255.25 and rounded to 255. With 16K block this becomes 511.5. This is persuasively looks like <strong>default_cardinality/32</strong>. One more reason to think the value comes from default statistics assumptions shown in the below CBO trace which is generated by this simple query.</p>
<blockquote><p><code>select distinct column_value from table(test_statement.getList1);</code></p></blockquote>
<p>The CBO trace in this case has following number of <strong>distinct values</strong> taken from the default statistics of the collection. If this is so, it explains how CBO arrives at the cardinality of the uniquely sorted collection values in the above calculation.</p>
<blockquote><p><code>BASE STATISTICAL INFORMATION</code><br />
<code>***********************</code><br />
<code>Table Stats::</code><br />
<code>  Table: KOKBF$  Alias: KOKBF$  (NOT ANALYZED)</code><br />
<code>    #Rows: 8168  #Blks:  100  AvgRowLen:  100.00</code><br />
<code>  Column (#1): KOKBC$(VARCHAR2)  NO STATISTICS (using defaults)</code><br />
<code>    AvgLen: 1.00 <strong>NDV: 255</strong> Nulls: 0 Density: 0.0039177</code></p></blockquote>
<p>But I will shut up about it for now until I find out this for certain. Now let’s see what the second form of the testing queries produce.</p>
<p><strong><em>Test 1.2:</em></strong></p>
<blockquote><p><code>select /*+ gather_plan_statistics */</code><br />
<code> t1.object_name,t1.object_type   from t1, table(cast(test_statement.getList1 as table_of_number)) nlist1</code><br />
<code>where t1.object_id = nlist1.column_value</code><br />
<code></code><br />
<code>Plan:</code><br />
<code></code><br />
<code>------------------------------------------------------------------------------------------------------------------</code><br />
<code>| Id  | Operation                          | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |</code><br />
<code>------------------------------------------------------------------------------------------------------------------</code><br />
<code>|   1 |  <strong>NESTED LOOPS</strong>                      |          |      1 |   <strong>8168</strong> |   <strong>1333K</strong>|<strong>01:27:04.70</strong> |    5422K|   2692K|</code><br />
<code>|   2 |   COLLECTION ITERATOR PICKLER FETCH| GETLIST1 |      1 |   <strong><font color="#0000ff">8168</font></strong> |   <strong>2000K</strong>|00:00:06.30 |       0 |      0 |</code><br />
<code>|   3 |   TABLE ACCESS BY INDEX ROWID      | T1       |   2000K|      1 |   1333K|<strong>01:26:51.90</strong> |    5422K|   2692K|</code><br />
<code>|*  4 |    <strong>INDEX UNIQUE SCAN</strong>               | T1_I     |   2000K|      1 |   1333K|00:05:39.05 |    4088K|   1382K|</code><br />
<code>------------------------------------------------------------------------------------------------------------------</code><br />
<code></code><br />
<code>Predicate Information (identified by operation id):</code><br />
<code>---------------------------------------------------</code><br />
<code></code><br />
<code>   4 - access("T1"."OBJECT_ID"=VALUE(KOKBF$))</code></p></blockquote>
<p>In this case the <strong>default cardinality</strong> of the 8168 rows of the collection was left intact. The plan didn’t change from Nested Loops for obvious reasons. The time and number of reads skyrocketed. This happened because the collection values were randomly chosen and not sorted as they were in the previous example. Access of the base table became more scattered and subsequently more reads took place. If a key value distribution is known and clustered, <strong>it might be worth using co-located values in collections</strong>.</p>
<p>Now it’s time to move on to the different settings. To change CBO default cardinality estimation this query uses officially unsupported <strong>CARDINALITY hint</strong>. You should ask Oracle permission to use it in production.</p>
<p><strong><em>Test 2.1 (adjusted cardinality):</em></strong></p>
<blockquote><p><code>select /*+ gather_plan_statistics */        t1.object_name,t1.object_type   from t1  where</code><br />
<code>t1.object_id in        (select /*+ cardinality(nlist1 1800000) */ *           from table(cast(test_statement.getList1 as table_of_number)) nlist1)</code><br />
<code></code><br />
<code>Plan:</code><br />
<code></code><br />
<code>----------------------------------------------------------------------------------------------------------------------------</code><br />
<code>| Id  | Operation                           | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |</code><br />
<code>----------------------------------------------------------------------------------------------------------------------------</code><br />
<code>|   1 |  NESTED LOOPS                       |          |      1 |    <strong>255</strong> |   <strong>1252K</strong>|00:01:37.31 |    5092K|    172K|   2959 |</code><br />
<code>|   2 |   </code><code>SORT</code><code> UNIQUE                       |          |      1 |    <strong><font color="#0000ff">255</font></strong> |   <strong>1878K</strong>|00:00:27.63 |     160 |   2970 |   2959 |</code><br />
<code>|   3 |    COLLECTION ITERATOR PICKLER FETCH| GETLIST1 |      1 |        |   2000K|00:00:04.32 |     129 |     11 |      0 |</code><br />
<code>|   4 |   TABLE ACCESS BY INDEX ROWID       | T1       |   1878K|      1 |   1252K|00:01:04.31 |    5091K|    169K|      0 |</code><br />
<code>|*  5 |    INDEX UNIQUE SCAN                | T1_I     |   1878K|      1 |   1252K|00:00:23.96 |    3839K|  23944 |      0 |</code><br />
<code>----------------------------------------------------------------------------------------------------------------------------</code><br />
<code></code><br />
<code>Predicate Information (identified by operation id):</code><br />
<code>---------------------------------------------------</code><br />
<code></code><br />
<code>   5 - access("T1"."OBJECT_ID"=VALUE(KOKBF$))</code></p></blockquote>
<p>No changes in the plan and statistics. What happened?! Did CBO even considered the change? Let’s take a look at the CBO trace.</p>
<blockquote><p><code>***********************</code><br />
<code>Table Stats::</code><br />
<code>  Table: KOKBF$  Alias: KOKBF$  (NOT ANALYZED)</code><br />
<code>    #Rows: 8168  #Blks:  100  AvgRowLen:  100.00</code><br />
<code>***************************************</code><br />
<code>SINGLE TABLE ACCESS PATH</code><br />
<code>  No statistics type defined for function TEST_STATEMENT</code><br />
<code>  Table: KOKBF$  Alias: KOKBF$</code><br />
<code>    <strong>Card: Original: 8168    &gt;&gt; Single Tab Card adjusted from: 8168.00  to: 1800000.00</strong></code><br />
<code>  Rounded: 1800000  Computed: 1800000.00  Non Adjusted: 8168.00</code></p></blockquote>
<p>It has obviously mentioned the hint value. But the final cardinality got value as before for the same reason of collection being processed as part of <strong>“IN” sub-query</strong>. I&#8217;ll get back to this a little later.</p>
<p>Alright, let’s see what the second form would be like.</p>
<p><strong><em>Test 2.2 (adjusted cardinality):</em></strong></p>
<blockquote><p><code>select /*+ gather_plan_statistics cardinality(nlist1 1800000) */</code><br />
<code>t1.object_name,t1.object_type   from t1, table(cast(test_statement.getList1 as table_of_number)) nlist1  where t1.object_id = nlist1.column_value</code><br />
<code></code><br />
<code>Plan:</code><br />
<code></code><br />
<code>---------------------------------------------------------------------------------------------------------------------------</code><br />
<code>| Id  | Operation                          | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |</code><br />
<code>---------------------------------------------------------------------------------------------------------------------------</code><br />
<code>|*  1 |  HASH JOIN                         |          |      1 |   <strong>1800K</strong>|   <strong>1333K</strong>|00:01:37.68 |     145K|    189K|  45724 |</code><br />
<code>|   2 |   COLLECTION ITERATOR PICKLER FETCH| GETLIST1 |      1 |   <strong><font color="#0000ff">1800K</font></strong>|   <strong>2000K</strong>|00:00:04.22 |       0 |      0 |      0 |</code><br />
<code>|   3 |   TABLE ACCESS FULL                | T1       |      1 |     10M|     10M|00:00:31.42 |     145K|    143K|      0 |</code><br />
<code>---------------------------------------------------------------------------------------------------------------------------</code><br />
<code></code><br />
<code>Predicate Information (identified by operation id):</code><br />
<code>---------------------------------------------------</code><br />
<code></code><br />
<code>   1 - access("T1"."OBJECT_ID"=VALUE(KOKBF$))</code></p></blockquote>
<p>Now, the hinted cardinality is in the final execution plan. And no wonder the CBO switched the plan from <strong>Nested Loops</strong> to <strong>Hash Join</strong>. Compare the logical and physical reads of this test and tests 1.1 and 2.1. If I would have allowed bigger hash area for this query, it could run in-memory and show even better results. Last test for this post is suppose to fix the query with the sub-query. For this we would need to do an additional modification. This time modification of the CBO parameter <strong>“_always_semi_join”</strong> is needed.</p>
<p><strong><em>Test 3.1: (adjusted cardinality, “_always_semi_join”=off):</em></strong></p>
<blockquote><p><code>select /*+ gather_plan_statistics */        t1.object_name,t1.object_type   from t1  where</code><br />
<code>t1.object_id in        (select /*+ cardinality(nlist1 1800000) */ *           from table(cast(test_statement.getList1 as table_of_number)) nlist1)</code><br />
<code></code><br />
<code>Plan:</code><br />
<code></code><br />
<code>-----------------------------------------------------------------------------------------------------------------------------</code><br />
<code>| Id  | Operation                            | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  | Writes |</code><br />
<code>-----------------------------------------------------------------------------------------------------------------------------</code><br />
<code>|*  1 |  HASH JOIN                           |          |      1 |   1800K|   1252K|00:01:26.75 |     145K|    195K|  50757 |</code><br />
<code>|   2 |   VIEW                               | VW_</code><code>NSO</code><code>_1 |      1 |   <strong>1800K</strong>|   <strong>1878K</strong>|00:00:11.52 |       0 |   6825 |   6825 |</code><br />
<code>|   3 |    HASH UNIQUE                       |          |      1 |   <strong>1800K</strong>|   <strong>1878K</strong>|00:00:09.64 |       0 |   6825 |   6825 |</code><br />
<code>|   4 |     COLLECTION ITERATOR PICKLER FETCH| GETLIST1 |      1 |   <strong><font color="#0000ff">1800K</font></strong>|   2000K|00:00:04.24 |       0 |      0 |      0 |</code><br />
<code>|   5 |   TABLE ACCESS FULL                  | T1       |      1 |     10M|     10M|00:00:31.40 |     145K|    144K|      0 |</code><br />
<code>-----------------------------------------------------------------------------------------------------------------------------</code><br />
<code></code><br />
<code>Predicate Information (identified by operation id):</code><br />
<code>---------------------------------------------------</code><br />
<code></code><br />
<code>   1 - access("T1"."OBJECT_ID"="COLUMN_VALUE")</code></p></blockquote>
<p>Why, you might ask, the <strong>Semi Join</strong> parameter has any effect on this? In pre evaluation phase CBO tries to apply different query rewrite techniques in order to optimize the query. One of them is <strong>unnesting sub-query</strong>. In this case it can either do Semi Join or <strong>unnest</strong> the sub-query as a <strong>set</strong> (collection of <strong>distinct</strong> values). Since the Semi Join is disabled it used the later. The sub-query took following form with cardinality hint propagated to the outer query.</p>
<blockquote><p><code>SELECT "T1"."OBJECT_NAME" "OBJECT_NAME","T1"."OBJECT_TYPE" "OBJECT_TYPE" FROM  (SELECT /*+ </code><code><strong>OPT</strong></code><code><strong>_ESTIMATE (TABLE "KOKBF$" ROWS=1800000.000000 )</strong> */ DISTINCT VALUE(KOKBF$) "COLUMN_VALUE" FROM TABLE(CAST("TEST"."TEST_STATEMENT"."GETLIST1"() AS "TABLE_OF_NUMBER") ) "KOKBF$") "VW_</code><code>NSO</code><code>_1","TEST"."T1" "T1" WHERE "T1"."OBJECT_ID"="VW_</code><code>NSO</code><code>_1"."COLUMN_VALUE"</code></p></blockquote>
<p>Basically the original query was rewritten into following form. It is similar to the second original form with the exception of <strong>distinct</strong> clause. Cardinality hint was not ignored as it was in the original query and CBO generated desired plan.</p>
<blockquote><p><code>select /*+ cardinality(nlist1 1800000) */</code><br />
<code>       t1.object_name,t1.object_type</code><br />
<code>  from t1</code><br />
<code>     , (select <strong>distinct</strong> column_value from table(cast(test_statement.getList1 as table_of_number))) nlist1</code><br />
<code> where t1.object_id = nlist1.column_value;</code></p></blockquote>
<p>Few words in conclusion. When tuning these queries, make sure CBO doesn’t rely on <strong>default statistics</strong>. In most cases CBO will subsequently generate sub-optimal plan, i.e. NLs instead of desired HJ or vice versa. If you cannot disable <strong>Semi Join</strong>, <strong>unnest</strong> “IN” sub-query. When tuning “IN” sub-query, use cardinality value close to the <strong>number of distinct </strong>elements, because that is what CBO will use in its calculations. If distribution of table data is <strong>deterministic</strong>, <strong>co-locate the values</strong> of the joined collection whenever possible to increase <strong>clustering of the access operation</strong>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vsadilovskiy.wordpress.com/2007/10/25/tuning-collections-in-queries-1/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">9</post-id>
		<media:content url="https://2.gravatar.com/avatar/b9e5109c7f24696d3d064bad5b582fbed3cfa2cec3570a1b526c4908099c3551?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Vlad Sadilovskiy</media:title>
		</media:content>
	</item>
		<item>
		<title>ORA-01461: can bind a LONG value only for insert into a LONG column</title>
		<link>https://vsadilovskiy.wordpress.com/2007/10/19/ora-01461-can-bind-a-long-value-only-for-insert-into-a-long-column/</link>
					<comments>https://vsadilovskiy.wordpress.com/2007/10/19/ora-01461-can-bind-a-long-value-only-for-insert-into-a-long-column/#comments</comments>
		
		<dc:creator><![CDATA[Vlad Sadilovskiy]]></dc:creator>
		<pubDate>Fri, 19 Oct 2007 20:47:25 +0000</pubDate>
				<category><![CDATA[Configuration]]></category>
		<category><![CDATA[JDBC]]></category>
		<category><![CDATA[multi-byte character set]]></category>
		<category><![CDATA[Troubleshooting]]></category>
		<guid isPermaLink="false">http://vsadilovskiy.wordpress.com/2007/10/19/ora-01461-can-bind-a-long-value-only-for-insert-into-a-long-column/</guid>

					<description><![CDATA[Just one another issue with JDBC I think is worth mentioning. You perhaps wonder why so obvious error message could be troublesome to comprehend. Unfortunately, it speaks of things that a developer never meant to happen. It doesn&#8217;t have to be a LONG value. This error could appear when ASCII strings are bound for VARCHAR2 columns. In this [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Just one another issue with JDBC I think is worth mentioning. You perhaps wonder why so obvious error message could be troublesome to comprehend. Unfortunately, it speaks of things that a developer never meant to happen. It doesn&#8217;t have to be a <strong>LONG</strong> value. This error could appear when <strong>ASCII</strong> strings are bound for <strong>VARCHAR2 </strong>columns. In this case it happens when <strong>JDBC v. 10.1/2</strong> is used with a <strong>Oracle Server 9i </strong>database configured for <strong>multi-byte </strong>character set. Before going any further, please note that according to support matrix Oracle JDBC 10g and 9i are cross supported with Oracle Server 9i and 10g. <span id="more-21"></span></p>
<p>For the testing I used two databases Oracle 10g and Oracle 9i with database character set <strong>UTF8</strong> and <strong>JDBC 10.2.0.3</strong>.</p>
<p>Some of the Asian language characters can consume up to 3 bytes in UTF8 encoding. But can you expect that a string composed of 1334 ASCII characters would not bind for VARCHAR2(4000)? However, it is possible. Let&#8217;s dig up little more details.</p>
<p>Here is how the string of <strong>4000</strong> &#8220;a&#8221; characters would appear to the <strong>Oracle 9i</strong>when bound from JDBC 10g with default properties. This bind is not spooled into the <strong>10046</strong> <strong>trace</strong> file. Instead it can be captured by enabling stacktrace dump on <strong>1461</strong> event.</p>
<blockquote><p><code><br />
 bind 19: <strong><em>dty=1</em></strong> <strong><em>mxl=<font color="#ff0000">4001(12000) </font></em></strong>mal=00 scl=00 pre=00 oacflg=03 oacfl2=10 <strong>size=4000</strong> offset=0<br />
   bfp=ffffffff7cd7f060 <strong><em>bln=4000</em></strong> <strong><em>avl=00</em></strong>flg=05<br />
</code></p></blockquote>
<p><strong><em>Oracle Server 10g</em></strong>. Note, that when you test this scenario, there are no errors &#8211; Oracle Server 10g  is perfectly fine with the <strong>12000</strong> bytes in the private buffer.</p>
<blockquote><p><code><br />
 Bind#19<br />
  <strong><em>oacdty=01</em></strong> <strong><em>mxl=<font color="#ff0000">4001(12000) </font></em></strong>mxlc=00 mal=00 scl=00 pre=00<br />
  oacflg=03 fl2=1000010 frm=01 <em><strong>csi=871</strong></em> <strong>siz=4000</strong> off=0<br />
  kxsbbbfp=ffffffff7b55a0c0  <strong><em>bln=4000</em></strong>  avl=4000  flg=05<br />
  value="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa....<br />
</code></p></blockquote>
<p>According to Metalink Note: 3756847.8 this problem was introduced in some <strong>10.1 </strong>versions of JDBC, but was fixed in <strong>10.2</strong>. However, it is not enabled by default. Following JDBC connection property enables the fix.</p>
<blockquote><p><code><br />
java.util.Properties props = new java.util.Properties();<br />
props.put<strong><em>("oracle.jdbc.RetainV9LongBindBehavior","true");</em></strong><br />
ods.setConnectionProperties(props);<br />
ods.setURL(url);<br />
</code></p></blockquote>
<p>And here is how the bind looks like after the fix is enabled.<br />
<strong><em> </em></strong></p>
<p><strong><em>Oracle Server 9i</em></strong>:</p>
<blockquote><p><code><br />
bind 19: <strong><em>dty=1</em></strong> <strong><em>mxl=4000(4000) </em></strong>mal=00 scl=00 pre=00 oacflg=03 oacfl2=10 <strong><em>size=4000</em></strong> offset=0<br />
   bfp=ffffffff7cd56088 <strong><em>bln=4000</em></strong> <strong><em>avl=4000 </em></strong>flg=05<br />
   value="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...<br />
</code></p></blockquote>
<p><strong><em>Oracle Server 10g</em></strong>:</p>
<blockquote><p><code><br />
 Bind#19<br />
  <strong><em>oacdty=01 mxl=<font color="#000000">4000(4000) </font></em></strong>mxlc=00 mal=00 scl=00 pre=00<br />
  oacflg=03 fl2=1000010 frm=01 <strong><em>csi=871 siz=4000</em></strong> off=0<br />
  kxsbbbfp=ffffffff7b56f060  <strong><em>bln=4000</em></strong> <strong><em>avl=4000</em></strong>flg=05<br />
  value="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...<br />
</code></p></blockquote>
<p>There is no need in enabling this fix for 10g/10g setup. 10g version of the trace is shown just for comparison purposes.</p>
<p>In conclusion I want to clarify that this article describes the unexpected behavior with legitimate length values. However, there are other cases when apparently correct values fail to insert with same message. I.e. already mentioned strings that, when using UTF8 for database character set, can expand from 4000 Asian language characters to up to 12000 byte values. In these cases, Notes: <a href="https://metalink.oracle.com/metalink/plsql/ml2_documents.showDocument?p_database_id=NOT&amp;p_id=241358.1">241358.1</a>, <a href="https://metalink.oracle.com/metalink/plsql/ml2_documents.showDocument?p_database_id=NOT&amp;p_id=370438.1">370438.1</a> recommend different workarounds. Note: <a href="https://metalink.oracle.com/metalink/plsql/ml2_documents.showDocument?p_database_id=NOT&amp;p_id=445072.1">445072.1</a>  has decent example of getting the length of encoded string and suggests converting <strong>VARCHAR2</strong> columns into <strong>CLOB </strong>if encoded string length exceeds maximum length of VARCHAR2 type.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vsadilovskiy.wordpress.com/2007/10/19/ora-01461-can-bind-a-long-value-only-for-insert-into-a-long-column/feed/</wfw:commentRss>
			<slash:comments>40</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">21</post-id>
		<media:content url="https://2.gravatar.com/avatar/b9e5109c7f24696d3d064bad5b582fbed3cfa2cec3570a1b526c4908099c3551?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Vlad Sadilovskiy</media:title>
		</media:content>
	</item>
		<item>
		<title>Tuning Collections in Queries [Introduction]</title>
		<link>https://vsadilovskiy.wordpress.com/2007/10/09/substituting-collections-for-in-list/</link>
					<comments>https://vsadilovskiy.wordpress.com/2007/10/09/substituting-collections-for-in-list/#comments</comments>
		
		<dc:creator><![CDATA[Vlad Sadilovskiy]]></dc:creator>
		<pubDate>Tue, 09 Oct 2007 23:13:35 +0000</pubDate>
				<category><![CDATA[Collections]]></category>
		<category><![CDATA[SQL Tuning]]></category>
		<category><![CDATA[Troubleshooting]]></category>
		<category><![CDATA[CBO]]></category>
		<category><![CDATA[SQL tuning]]></category>
		<guid isPermaLink="false">http://vsadilovskiy.wordpress.com/2007/10/09/substituting-collections-for-in-list/</guid>

					<description><![CDATA[[To Next Article [1]] [To Performance Study] If you never heard of using collections instead of regular IN-LIST expressions, you might want to read varying elements in IN list article from AskTom. It unfortunately has little information about the way CBO treats collections. So, if you have problems with tuning queries that employ nested tables or just evaluating what is in the way please read on. [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>[<a href="https://vsadilovskiy.wordpress.com/2007/10/25/tuning-collections-in-queries-1/"><font color="#0000ff">To Next Article [1]</font></a>] [<a href="https://vsadilovskiy.wordpress.com/substituting-a-collection-for-in-list-performance-study/"><font color="#0000ff">To Performance Study</font></a>]</p>
<p>If you never heard of using collections instead of regular <strong>IN-LIST</strong> expressions, you might want to read <a target="_blank" href="http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:110612348061" title="varying elements in IN list">varying elements in IN list</a> article from AskTom. It unfortunately has little information about the way <strong>CBO</strong> treats <strong>collections</strong>. So, if you have problems with tuning queries that employ nested tables or just evaluating what is in the way please read on. <span id="more-6"></span>Here is one of the basic forms of SQL queries that employ collections.</p>
<blockquote><p><code>select *<br />
  from t1<br />
 where t1.object_id in<br />
     (<br />
       select *<br />
         from table(cast(:1 as table_of_number))<br />
     );</code></p></blockquote>
<p>There are several optimization issues related to tuning queries that use collections. Many of them can be attributed to the CBO <strong>statistical assumptions</strong>. The CBO calculations and figures are a little different in 9i and 10g. However the issue might have change the appearance, but not the essence. There will be few more posts on some basic forms of queries with collections.</p>
<p>Over the past three years I&#8217;ve engaged with the Oracle TS several times to find a good resolution for this nuisance. That generated couple bugs: <a target="new" href="https://metalink.oracle.com/metalink/plsql/ml2_documents.showFrameDocument?p_database_id=BUG&amp;p_id=4484645">4484645</a>, <a href="https://metalink.oracle.com/metalink/plsql/f?p=130:4:::::p4_database_id,p4_docid,p4_show_header,p4_show_help,p4_black_frame,p4_font:BUG,4235962,1,1,1,helvetica">4235962</a>. One of them is closed as &#8220;NOT A BUG&#8221;.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vsadilovskiy.wordpress.com/2007/10/09/substituting-collections-for-in-list/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">6</post-id>
		<media:content url="https://2.gravatar.com/avatar/b9e5109c7f24696d3d064bad5b582fbed3cfa2cec3570a1b526c4908099c3551?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Vlad Sadilovskiy</media:title>
		</media:content>
	</item>
		<item>
		<title>Blog theme</title>
		<link>https://vsadilovskiy.wordpress.com/2007/10/09/bolg-theme/</link>
					<comments>https://vsadilovskiy.wordpress.com/2007/10/09/bolg-theme/#comments</comments>
		
		<dc:creator><![CDATA[Vlad Sadilovskiy]]></dc:creator>
		<pubDate>Tue, 09 Oct 2007 21:42:17 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://vsadilovskiy.wordpress.com/2007/10/09/bolg-theme/</guid>

					<description><![CDATA[I know, I know&#8230; The theme looks exactly like the one Jonathan Lewis has for his Scratchpad. Sorry, about that. I&#8217;ve tried every possibility and this is the only one that is comfortable for posting Oracle trace or code snippets. The closest thing I found that wouldn&#8217;t wrap the code is a Sandbox theme. Others would [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>I know, I know&#8230; The theme looks exactly like the one Jonathan Lewis has for his Scratchpad. Sorry, about that. I&#8217;ve tried every possibility and this is the only one that is comfortable for posting Oracle trace or code snippets. The closest thing I found that wouldn&#8217;t wrap the code is a Sandbox theme. Others would have very small or otherwise irritating font.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vsadilovskiy.wordpress.com/2007/10/09/bolg-theme/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">7</post-id>
		<media:content url="https://2.gravatar.com/avatar/b9e5109c7f24696d3d064bad5b582fbed3cfa2cec3570a1b526c4908099c3551?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Vlad Sadilovskiy</media:title>
		</media:content>
	</item>
		<item>
		<title>&#8220;Undocumented?!&#8221; &#8211; Use it or not</title>
		<link>https://vsadilovskiy.wordpress.com/2007/10/09/5/</link>
					<comments>https://vsadilovskiy.wordpress.com/2007/10/09/5/#comments</comments>
		
		<dc:creator><![CDATA[Vlad Sadilovskiy]]></dc:creator>
		<pubDate>Tue, 09 Oct 2007 05:06:19 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://vsadilovskiy.wordpress.com/2007/10/09/5/</guid>

					<description><![CDATA[Rainy day&#8230; Thoughts arn&#8217;t well aligned&#8230; At the end of the day I was wondering on the Internet searching for an inspiration. For a moment I thought I found something interesting. It was on the Jonathan Lewis&#8217;s blog &#8211; something about Oracle traces. But just a second later after finished reading I grasped what the message was about. In [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Rainy day&#8230; Thoughts arn&#8217;t well aligned&#8230; At the end of the day I was wondering on the Internet searching for an inspiration. For a moment I thought I found something interesting. It was on the Jonathan Lewis&#8217;s blog &#8211; something about Oracle traces. But just a second later after finished reading I grasped what the message was about. In few words there was confusion, doubt and something else, or so it seemed. The title was <a target="_blank" href="http://jonathanlewis.wordpress.com/2007/09/03/trace-files/" title="Trace Files">Trace Files</a>. And here you go an inspiration came, and as usual from a direction you&#8217;d never expect. <span id="more-5"></span></p>
<p>Should we use undocumented or unofficial methods? Yes, no doubt. That is of course when they are judicially legitimate. I just wanted to point out few key elements of the documented versus undocumented approach as I understand and interpret it. In a different scope this might become discussion about supported versus unsupported and so on.</p>
<p>Documentation is a right place to go if it exists. If it doesn&#8217;t, &#8220;hacking&#8221; in the right meaning of the word, is the way to know the system better than it can possibly be documented. Consider Oracle tracing facility as free of charge and supported debugger. By using it you&#8217;d learn about the Oracle and application that uses Oracle, about specifics of different Oracle versions, the improvements in newer releases and deficiencies in former releases.</p>
<p> What you would lack when you use Oracle tracing is official evidence. If you see a problem in the trace, but struggle to reproduce it using documented forms of proof, you might have some trouble building a case for an SR. You also will have certain difficulties explaining it to the Oracle TS what is that you are trying to solve. And final point against it, when filing SR, is that in Oracle R&amp;D work people just like you. Reverse enginiring an issue from a trace file that you attached is the last thing they wanted to do. Similar to any other trace whether that is a stack trace from JVM or a core dump. It is always better for them to have a reproducible at will test case. However, many times by looking at traces I found things to build a simple test case that I wouldn&#8217;t have gotten that easily otherwise.</p>
<p>To summarize, as far as I&#8217;m concerned, if the Oracle traces, considering their generation can be done using supported API, allow me to find true problems and do right decisions I&#8217;ll keep using them even if their format is neither documented nor supported.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vsadilovskiy.wordpress.com/2007/10/09/5/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5</post-id>
		<media:content url="https://2.gravatar.com/avatar/b9e5109c7f24696d3d064bad5b582fbed3cfa2cec3570a1b526c4908099c3551?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Vlad Sadilovskiy</media:title>
		</media:content>
	</item>
		<item>
		<title>Statement Cache causes OutOfMemoryError (JDBC)</title>
		<link>https://vsadilovskiy.wordpress.com/2007/10/08/3/</link>
					<comments>https://vsadilovskiy.wordpress.com/2007/10/08/3/#comments</comments>
		
		<dc:creator><![CDATA[Vlad Sadilovskiy]]></dc:creator>
		<pubDate>Mon, 08 Oct 2007 03:39:42 +0000</pubDate>
				<category><![CDATA[JDBC]]></category>
		<category><![CDATA[Troubleshooting]]></category>
		<guid isPermaLink="false">http://vsadilovskiy.wordpress.com/2007/10/08/3/</guid>

					<description><![CDATA[How efficient parse one &#8211; execute many in JDBC can get? So obvious recommendation to keep PreparedStatement open as long as possible is not easy. Testing custom built statement cache solution proved it to be not very well scalable. Increasing number of concurrent connections or the size of the cache of open statements lead to ineviable OutOfMemoryError [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>How efficient parse one &#8211; execute many in JDBC can get? So obvious recommendation to keep PreparedStatement open as long as possible is not easy. Testing custom built statement cache solution proved it to be not very well scalable. Increasing number of concurrent connections or the size of the cache of open statements lead to ineviable OutOfMemoryError exceptions.<span id="more-3"></span></p>
<p>I noticed during my testing by fetching from different &#8220;width&#8221; tables and playing with prefetch row count, that the wider the row or higher prefetch count were the faster my cache had grown. I debugged my code for many hours looking whether I was closing result sets or for something else very obvious. Nope, no luck &#8211; everything was correct. And yet OOME was consistent.</p>
<p>In the end it appeared that <span>JDBC OracleStatement kept reference to so called accessors&#8217; arrays (like a cache of prefetched rows data) for a result set that had been last executed even when the result set was already closed. The size of that data was proportional to the product of the fetched data (in my tests table) width and prefetch row count. I&#8217;ve tried then JDBC implicit and explicit caching and was showing <strong>precisely</strong> same memory footprint.</span></p>
<p>Opened SR and after few weeks was advised by a nice Oracle TS lady that there could be one workaround (which is mentioned above). It was to use property <strong>FreeMemoryOnEnterImplicitCache</strong> and so instead of this:</p>
<p><code>conn = (OracleConnection) DriverManager.getConnection(url, user, password);</code></p>
<p>use this</p>
<p><code>OracleDataSource ods = new OracleDataSource();</code><code>Properties props = new Properties();<br />
props.put("user", user);<br />
props.put("password", password);<br />
props.put("oracle.jdbc.FreeMemoryOnEnterImplicitCache", true);<br />
ods.setConnectionProperties(props);<br />
ods.setURL(url);<br />
conn = ods.getConnection();</code></p>
<p>During testing I didn&#8217;t find a way a custom or explicit cache with key can be used effectively, especially if they are LRU caches (the later appeared to be LRU type of cache) &#8211; that residue data is going to get into OldGeneration before the statement is reused and the arrays are repopulated. I really hope the &#8220;bug&#8221; is going to be fixed in JDBC 10.2.0.4.</p>
<p>Metalink bug reference: <a target="new" href="https://metalink.oracle.com/metalink/plsql/ml2_documents.showFrameDocument?p_database_id=BUG&amp;p_id=6082980">6082980</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://vsadilovskiy.wordpress.com/2007/10/08/3/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">3</post-id>
		<media:content url="https://2.gravatar.com/avatar/b9e5109c7f24696d3d064bad5b582fbed3cfa2cec3570a1b526c4908099c3551?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Vlad Sadilovskiy</media:title>
		</media:content>
	</item>
	</channel>
</rss>
