<?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>Engin ÖZER&#039;s Blog</title>
	<atom:link href="http://enginozer.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://enginozer.wordpress.com</link>
	<description>Knowledge = Power</description>
	<lastBuildDate>Fri, 13 Nov 2009 15:53:58 +0000</lastBuildDate>
	<generator>http://wordpress.com/</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<cloud domain='enginozer.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://www.gravatar.com/blavatar/69d65b1c36e74dcd7a348e2272e41a90?s=96&#038;d=http://s.wordpress.com/i/buttonw-com.png</url>
		<title>Engin ÖZER&#039;s Blog</title>
		<link>http://enginozer.wordpress.com</link>
	</image>
			<item>
		<title>Oracle Forms Triggers</title>
		<link>http://enginozer.wordpress.com/2009/11/13/oracle-forms-triggers/</link>
		<comments>http://enginozer.wordpress.com/2009/11/13/oracle-forms-triggers/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 15:44:02 +0000</pubDate>
		<dc:creator>Engin ÖZER</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://enginozer.wordpress.com/?p=66</guid>
		<description><![CDATA[At this article i will try to mention about Forms&#8217; special triggers on various types. We will examine them in three sections; Form level triggers, Data block level triggers and Item level triggers.
Form Level Triggers;
When-New-Form-Instance: This trigger is called just after form is called. So you can do everything you need to do before the [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=66&subd=enginozer&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>At this article i will try to mention about Forms&#8217; special triggers on various types. We will examine them in three sections; Form level triggers, Data block level triggers and Item level triggers.</p>
<p><strong>Form Level Triggers;</strong></p>
<p><strong>When-New-Form-Instance:</strong> This trigger is called just after form is called. So you can do everything you need to do before the form starts. Be careful that this trigger is called only when the form is opened.</p>
<p><strong>When-Form-Navigate:</strong> This trigger is helpful when you need to open a new form(as new program) from a from. This trigger is called when navigating between those forms.</p>
<p>&nbsp;</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/enginozer.wordpress.com/66/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/enginozer.wordpress.com/66/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/enginozer.wordpress.com/66/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/enginozer.wordpress.com/66/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/enginozer.wordpress.com/66/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/enginozer.wordpress.com/66/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/enginozer.wordpress.com/66/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/enginozer.wordpress.com/66/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/enginozer.wordpress.com/66/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/enginozer.wordpress.com/66/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=66&subd=enginozer&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://enginozer.wordpress.com/2009/11/13/oracle-forms-triggers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d115faa5b1011c2837cb2de5b694342f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">enginozer</media:title>
		</media:content>
	</item>
		<item>
		<title>Oracle Explain Plan &#8211; 2</title>
		<link>http://enginozer.wordpress.com/2009/09/25/oracle-explain-plan-2-2/</link>
		<comments>http://enginozer.wordpress.com/2009/09/25/oracle-explain-plan-2-2/#comments</comments>
		<pubDate>Fri, 25 Sep 2009 07:20:19 +0000</pubDate>
		<dc:creator>Engin ÖZER</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://enginozer.wordpress.com/?p=64</guid>
		<description><![CDATA[






  Interpreting Explain Plan  



What&#8217;s an explain plan?
An explain plan is a representation of the access path that is taken when a query is executed within Oracle.
Query processing can be divided into 7 phases:



[1] Syntactic
Checks the syntax of the query


[2] Semantic
Checks that all objects exist and are accessible


[3] View Merging
Rewrites query as join on base [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=64&subd=enginozer&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><table border="0" cellspacing="0" cellpadding="4" width="570">
<tbody>
<tr>
<td width="100" height="35" valign="top">
<p align="left"><a href="history.back()"><img src="http://enginozer.wordpress.com/img/zurueck.gif" border="0" alt="Zurück" width="76" height="19" /></a></p>
</td>
<th height="35" valign="top">
<p align="left"><img src="http://enginozer.wordpress.com/img/bullet-gruen.gif" alt="" width="15" height="10" />  Interpreting Explain Plan  <img src="http://enginozer.wordpress.com/img/bullet-gruen.gif" alt="" width="15" height="10" /></p>
</th>
</tr>
<tr>
<td colspan="2" valign="top">What&#8217;s an explain plan?</p>
<p>An explain plan is a representation of the access path that is taken when a query is executed within Oracle.</p>
<p>Query processing can be divided into 7 phases:</p>
<table border="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td width="25%" valign="top">[1] Syntactic</td>
<td width="75%" valign="top">Checks the syntax of the query</td>
</tr>
<tr>
<td width="25%" valign="top">[2] Semantic</td>
<td width="75%" valign="top">Checks that all objects exist and are accessible</td>
</tr>
<tr>
<td width="25%" valign="top">[3] View Merging</td>
<td width="75%" valign="top">Rewrites query as join on base tables as opposed to using views</td>
</tr>
<tr>
<td width="25%" valign="top">[4] Statement<br />
     Transformation</td>
<td width="75%" valign="top">Rewrites query transforming some complex constructs into simpler ones where appropriate (e.g. subquery merging, in/or transformation)</td>
</tr>
<tr>
<td width="25%" valign="top">[5] Optimization</td>
<td width="75%" valign="top">Determines the optimal access path for the query to take. With the Rule Based Optimizer (RBO) it uses a set of heuristics to determine access path. With the Cost Based Optimizer (CBO) we use statistics to analyze the relative costs of accessing objects.</td>
</tr>
<tr>
<td width="25%" valign="top">[6] QEP Generation</td>
<td width="75%" valign="top">QEP = Query Evaluation Plan</td>
</tr>
<tr>
<td width="25%" valign="top">[7] QEP Execution</td>
<td width="75%" valign="top">QEP = Query Evaluation Plan</td>
</tr>
</tbody>
</table>
<p>Steps [1]-[6] are handled by the parser. Step [7] is the execution of the statement.</p>
<p>The explain plan is produced by the parser. Once the access path has been decided upon it is stored in the library cache together with the statement itself. We store queries in the library cache based upon a hashed representation  of that query. When looking for a statement in the library cache, we first apply a hashing algorithm to the statement and then we look for this hash value in the library cache. This access path will be used until the query is reparsed.</p>
<p>Terminology</p>
<table border="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td width="25%">Row Source</td>
<td width="75%">A set of rows used in a query may be a select from a base object or the result set returned by joining 2 earlier row sources</td>
</tr>
<tr>
<td width="25%">Predicate</td>
<td width="75%">where clause of a query</td>
</tr>
<tr>
<td width="25%">Tuples</td>
<td width="75%">rows</td>
</tr>
<tr>
<td width="25%">Driving Table</td>
<td width="75%">This is the row source that we use to seed the query. If this returns a lot of rows then this can have a negative affect on all subsequent operations</td>
</tr>
<tr>
<td width="25%">Probed Table</td>
<td width="75%">This is the object we lookup data in after we have retrieved relevant key data from the driving table.</td>
</tr>
</tbody>
</table>
<p>How does Oracle access data?</p>
<p>At the physical level Oracle reads blocks of data. The smallest amount of data read is a single Oracle block, the largest is constrained by operating system limits (and multiblock i/o). Logically Oracle finds the data to read by using the following methods:</p>
<ul>
<li>Full Table Scan (FTS)</li>
<li>Index Lookup (unique &amp; non-unique)</li>
<li>Rowid</li>
</ul>
<p>Explain plan Hierarchy</p>
<p>Simple explain plan:</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT     [CHOOSE] Cost=1234<br />
  TABLE ACCESS FULL LARGE [:Q65001] [ANALYZED]</p>
<p>The rightmost uppermost operation of an explain plan is the first thing that the explain plan will execute. In this case TABLE ACCESS FULL LARGE is the first operation. This statement means we are doing a full table scan of table LARGE. When this operation completes then the resultant row source is passed up to the<br />
next level of the query for processing. In this case it is the SELECT STATEMENT which is the top of the query.</p>
<p>[CHOOSE] is an indication of the optimizer_goal for the query. This DOES NOT necessarily indicate that plan has actually used this goal. The only way to confirm this is to check the<br />
cost= part of the explain plan as well. For example the following query indicates that the CBO has been used because there is a cost in the cost field:</p>
<p>SELECT STATEMENT     [CHOOSE] Cost=1234</p>
<p>However the explain plan below indicates the use of the RBO because the cost field is blank:</p>
<p>SELECT STATEMENT     [CHOOSE] Cost=</p>
<p>The cost field is a comparative cost that is used internally to determine the best cost for particular plans. The costs of different statements are not really directly comparable.</p>
<p>[:Q65001] indicates that this particular part of the query is being executed in parallel. This number indicates that the operation will be processed by a parallel query slave as opposed to being executed serially.</p>
<p>[ANALYZED] indicates that the object in question has been analyzed and there are currently statistics available for the CBO to use. There is no indication of the &#8216;level&#8217; of analysis done.</p>
<p>Access Methods in detail</p>
<p>Full Table Scan (FTS)</p>
<p>In a FTS operation, the whole table is read up to the high water mark (HWM). The HWM marks the last block in the table that has ever had data written to it. If you have deleted all the rows then you will still read up to the HWM. Truncate resets the HWM back to the start of the table. FTS uses multiblock i/o to read the blocks from disk. Multiblock i/o is controlled by the parameter &lt;PARAM:db_block_multi_block_read_count&gt;.</p>
<p>This defaults to:</p>
<p>db_block_buffers / ( (PROCESSES+3) / 4 )</p>
<p>Maximum values are OS dependant</p>
<p>Buffers from FTS operations are placed on the Least Recently Used (LRU) end of the buffer cache so will be quickly aged out. FTS is not recommended for large tables unless you are reading &gt;5-10% of it (or so) or you intend to run in parallel.</p>
<p>Example FTS explain plan:</p>
<p>SQL&gt; explain plan for select * from dual;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT     [CHOOSE] Cost=<br />
  TABLE ACCESS FULL DUAL</p>
<p>Index lookup</p>
<p>Data is accessed by looking up key values in an index and returning rowids. A rowid uniquely identifies an individual row in a particular data block. This block is read via single block i/o.</p>
<p>In this example an index is used to find the relevant row(s) and then the table is accessed to lookup the ename column (which is not included in the index):</p>
<p>SQL&gt; explain plan for<br />
select empno,ename from emp where empno=10;<br />
Query Plan</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
TABLE ACCESS BY ROWID EMP [ANALYZED]<br />
    INDEX UNIQUE SCAN EMP_I1</p>
<p>Notice the &#8216;TABLE ACCESS BY ROWID&#8217; section. This indicates that the table data is not being accessed via a FTS operation but rather by a rowid lookup. In this case the rowid has been produced by looking up values in the index first. The index is being accessed by an &#8216;INDEX UNIQUE SCAN&#8217; operation. This is explained below. The index name in this case is EMP_I1. If all the required data resides in the index then a table lookup may be unnecessary and all you will see is an index access with no table access.</p>
<p>In the following example all the columns (empno) are in the index. Notice that no table access takes place:</p>
<p>SQL&gt; explain plan for<br />
select empno from emp where empno=10;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
  INDEX UNIQUE SCAN EMP_I1</p>
<p>Indexes are presorted so sorting may be unecessary if the sort order required is the same as the index.</p>
<p>SQL&gt; explain plan for select empno,ename from emp<br />
where empno &gt; 7876 order by empno;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
SELECT STATEMENT   [CHOOSE] Cost=1<br />
TABLE ACCESS BY ROWID EMP [ANALYZED]<br />
  INDEX RANGE SCAN EMP_I1 [ANALYZED]</p>
<p>In this case the index is sorted so ther rows will be returned in the order of the index hence a sort is unecessary.</p>
<p>SQL&gt; explain plan for<br />
select /*+ Full(emp) */ empno,ename from emp<br />
where empno&gt; 7876 order by empno;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
SELECT STATEMENT   [CHOOSE] Cost=9<br />
  SORT ORDER BY<br />
    TABLE ACCESS FULL EMP [ANALYZED]  Cost=1 Card=2 Bytes=66</p>
<p>Because we have forced a FTS the data is unsorted and so we must sort the data<br />
after it has been retrieved.</p>
<p>There are 4 methods of index lookup:</p>
<ul>
<li>index unique scan</li>
<li>index range scan</li>
<li>index full scan</li>
<li>index fast full scan</li>
</ul>
<p>Index unique scan</p>
<p>Method for looking up a single key value via a unique index. Always returns a single value You must supply AT LEAST the leading column of the index to access data via the index, However this may return &gt; 1 row as the uniqueness will not be guaranteed.</p>
<p>SQL&gt; explain plan for<br />
select empno,ename from emp where empno=10;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
TABLE ACCESS BY ROWID EMP [ANALYZED]<br />
    INDEX UNIQUE SCAN EMP_I1</p>
<p>Index range scan</p>
<p>Method for accessing multiple column values You must supply AT LEAST the leading column of the index to access data via the index Can be used for range operations (e.g. &gt; &lt; &lt;&gt; &gt;= &lt;= between)</p>
<p>SQL&gt; explain plan for select empno,ename from emp<br />
where empno &gt; 7876 order by empno;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
SELECT STATEMENT   [CHOOSE] Cost=1<br />
TABLE ACCESS BY ROWID EMP [ANALYZED]<br />
  INDEX RANGE SCAN EMP_I1 [ANALYZED]</p>
<p>A non-unique index may return multiple values for the predicate col1 = 5 and will use an index range scan</p>
<p>SQL&gt; explain plan for select mgr from emp where mgr = 5</p>
<p>Query plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
  INDEX RANGE SCAN EMP_I2 [ANALYZED]</p>
<p>Index Full Scan</p>
<p>In certain circumstances it is possible for the whole index to be scanned as opposed to a range scan (i.e. where no constraining predicates are provided for a table). Full index scans are  only available in the CBO as otherwise we are unable to determine whether a full scan would be a good idea or not. We choose an index Full Scan when we have statistics that indicate that it is going to be more efficient than a Full table scan and a sort.</p>
<p>For example we may do a Full index scan when we do an unbounded scan of an index and want the data to be ordered in the index order. The optimizer may decide that selecting all the information from the index and not sorting is more efficient than doing a FTS or a Fast Full Index Scan and then sorting.</p>
<p>An Index full scan will perform single block i/o&#8217;s and so it may prove to be inefficient. Index BE_IX is a concatenated index on big_emp (empno,ename)</p>
<p>SQL&gt; explain plan for select empno,ename<br />
     from big_emp order by empno,ename;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT   [CHOOSE] Cost=26<br />
  INDEX FULL SCAN BE_IX [ANALYZED]</p>
<p>Index Fast Full Scan</p>
<p>Scans all the block in the index Rows are not returned in sorted order Introduced in 7.3 and requires V733_PLANS_ENABLED=TRUE and CBO may be hinted using INDEX_FFS hint uses multiblock i/o can be executed in parallel can be used to access second column of concatenated indexes. This is because we are selecting all of the index.</p>
<p>Note that INDEX FAST FULL SCAN is the mechinism behind fast index create and recreate. Index BE_IX is a concatenated index on big_emp (empno,ename)</p>
<p>SQL&gt; explain plan for select empno,ename from big_emp;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT   [CHOOSE] Cost=1<br />
  INDEX FAST FULL SCAN BE_IX [ANALYZED]</p>
<p>Selecting the 2nd column of concatenated index:</p>
<p>SQL&gt; explain plan for select ename from big_emp;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT   [CHOOSE] Cost=1<br />
  INDEX FAST FULL SCAN BE_IX [ANALYZED]</p>
<p>Rowid</p>
<p>This is the quickest access method available Oracle simply retrieves the block specified and extracts the rows it is interested in. Most frequently seen in explain plans as Table access by Rowid</p>
<p>SQL&gt; explain plan for select * from dept where rowid = &#8216;:x&#8217;;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
TABLE ACCESS BY ROWID DEPT [ANALYZED]</p>
<p>Table is accessed by rowid following index lookup:</p>
<p>SQL&gt; explain plan for<br />
select empno,ename from emp where empno=10;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
TABLE ACCESS BY ROWID EMP [ANALYZED]<br />
    INDEX UNIQUE SCAN EMP_I1</p>
<p>Joins</p>
<p>A Join is a predicate that attempts to combine 2 row sources We only ever join 2 row sources together Join steps are always performed serially even though underlying row sources may have been accessed in parallel. Join order &#8211; order in which joins are performed</p>
<p>The join order makes a significant difference to the way in which the query is executed. By accessing particular row sources first, certain predicates may be satisfied that are not satisfied by with other join orders. This may prevent certain access paths from being taken.</p>
<p>Suppose there is a concatenated index on A(a.col1,a.col2). Note that a.col1 is the leading column. Consider the following query:</p>
<p>select A.col4<br />
from   A,B,C<br />
where  B.col3 = 10<br />
and    A.col1 = B.col1<br />
and    A.col2 = C.col2<br />
and    C.col3 = 5</p>
<p>We could represent the joins present in the query using the following schematic:</p>
<p>  B     &lt;&#8212;&gt; A &lt;&#8212;&gt;    C<br />
col3=10                col3=5</p>
<p>There are really only 2 ways we can drive the query: via B.col3 or C.col3. We would have to do a Full scan of A to be able to drive off it. This is unlikely to be efficient with large tables;</p>
<p>If we drive off table B, using predicate B.col3=10 (as a filter or lookup key) then we will retrieve the value for B.col1 and join to A.col1. Because we have now filled the leading column of the concatenated index on table A we can use this index to give us values for A.col2 and join to A.</p>
<p>However if we drive of table c, then we only get a value for a.col2 and since this is a trailing column of a concatenated index and the leading column has not been supplied at this point, we cannot use the index on a to lookup the data.</p>
<p>So it is likely that the best join order will be B A C. The CBO will obviously use costs to establish whether the individual access paths are a good idea or not.</p>
<p>If the CBO does not choose this join order then we can hint it by changing the from<br />
clause to read:</p>
<p>from B,A,C</p>
<p>and using the /*+ ordered */ hint. The resultant query would be:</p>
<p>select /*+ ordered */ A.col4<br />
from   B,A,C<br />
where  B.col3 = 10<br />
and    A.col1 = B.col1<br />
and    A.col2 = C.col2<br />
and    C.col3 = 5</p>
<p>Join Types</p>
<ul>
<li>Sort Merge Join (SMJ)</li>
<li>Nested Loops (NL)</li>
<li>Hash Join</li>
</ul>
<p>Sort Merge Join</p>
<p>Rows are produced by Row Source 1 and are then sorted Rows from Row Source 2 are then produced and sorted by the same sort key as Row Source 1. Row Source 1 and 2 are NOT accessed concurrently Sorted rows from both sides are then merged together (joined)</p>
<p>                   MERGE<br />
                 /      \<br />
            SORT        SORT<br />
             |             |<br />
        Row Source 1  Row Source 2</p>
<p>If the row sources are already (known to be) sorted then the sort operation is unecessary as long as both &#8217;sides&#8217; are sorted using the same key. Presorted row sources include indexed columns and row sources that have already been sorted in earlier steps. Although the merge of the 2 row sources is handled serially, the row sources could be accessed in parallel.</p>
<p>SQL&gt; explain plan for<br />
select /*+ ordered */ e.deptno,d.deptno<br />
from emp e,dept d<br />
where e.deptno = d.deptno<br />
order by e.deptno,d.deptno;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
SELECT STATEMENT [CHOOSE] Cost=17<br />
  MERGE JOIN<br />
    SORT JOIN<br />
      TABLE ACCESS FULL EMP [ANALYZED]<br />
    SORT JOIN<br />
      TABLE ACCESS FULL DEPT [ANALYZED]</p>
<p>Sorting is an expensive operation, especially with large tables. Because of this, SMJ is often not a particularly efficient join method.</p>
<p>Nested Loops</p>
<p>First we return all the rows from row source 1 Then we probe row source 2 once for each row returned from row source 1</p>
<p>Row source 1<br />
~~~~~~~~~~~~<br />
Row 1 &#8212;&#8212;&#8212;&#8212;&#8211;       &#8212; Probe -&gt;       Row source 2<br />
Row 2 &#8212;&#8212;&#8212;&#8212;&#8211;       &#8212; Probe -&gt;       Row source 2<br />
Row 3 &#8212;&#8212;&#8212;&#8212;&#8211;       &#8212; Probe -&gt;       Row source 2</p>
<p>Row source 1 is known as the outer table<br />
Row source 2 is known as the inner table</p>
<p>Accessing row source 2 is known a probing the inner table For nested loops to be efficient it is important that the first row source returns as few rows as possible as this directly controls the number of probes of the second row source. Also it helps if the access method for row source 2 is efficient as this operation is being repeated once for every row returned by row source 1.</p>
<p>SQL&gt; explain plan for<br />
select a.dname,b.sql<br />
from dept a,emp b<br />
where a.deptno = b.deptno;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
SELECT STATEMENT [CHOOSE] Cost=5<br />
  NESTED LOOPS<br />
    TABLE ACCESS FULL DEPT [ANALYZED]<br />
    TABLE ACCESS FULL EMP [ANALYZED]</p>
<p>Hash Join</p>
<p>New join type introduced in 7.3 More efficient in theory than NL &amp; SMJ Only accessible via the CBO Smallest row source is chosen and used to build a hash table and a bitmap The second row source is hashed and checked against the hash table looking for joins. The bitmap is used as a quick lookup to check if rows are in the hash table and are especially useful when the hash table is too large to fit in memory.</p>
<p>SQL&gt; explain plan for<br />
select /*+ use_hash(emp) */ empno<br />
from emp,dept<br />
where emp.deptno = dept.deptno;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
SELECT STATEMENT  [CHOOSE] Cost=3<br />
  HASH JOIN<br />
    TABLE ACCESS FULL DEPT<br />
    TABLE ACCESS FULL EMP</p>
<p>Hash joins are enabled by the parameter HASH_JOIN_ENABLED=TRUE in the init.ora or session. TRUE is the default in 7.3</p>
<p>Cartesian Product</p>
<p>A Cartesian Product is done where they are no join conditions between 2 row sources and there is no alternative method of accessing the data Not really a join as such as there is no join! Typically this is caused by a coding mistake where a join has been left out. It can be useful in some circumstances &#8211; Star joins uses cartesian products.</p>
<p>Notice that there is no join between the 2 tables:</p>
<p>SQL&gt; explain plan for<br />
select emp.deptno,dept,deptno<br />
from emp,dept</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SLECT STATEMENT [CHOOSE] Cost=5<br />
  MERGE JOIN CARTESIAN<br />
    TABLE ACCESS FULL DEPT<br />
    SORT JOIN<br />
      TABLE ACCESS FULL EMP</p>
<p>The CARTESIAN keyword indicate that we are doing a cartesian product.</p>
<p>Operations</p>
<p>Operations that show up in explain plans</p>
<ul>
<li>sort</li>
<li>filter</li>
<li>view</li>
</ul>
<p>Sorts</p>
<p>There are a number of different operations that promote sorts</p>
<ul>
<li>order by clauses</li>
<li>group by</li>
<li>sort merge join</li>
</ul>
<p>Note that if the row source is already appropriately sorted then no sorting is required. This is now indicated in 7.3:</p>
<p>SORT GROUP BY NOSORT<br />
     INDEX FULL SCAN &#8230;..</p>
<p>In this case the group by operation simply groups the rows it does not do the sort operation as this has already been completed.</p>
<p>Sorts are expensive operations especially on large tables where the rows do not fit in memory and spill to disk. By default sort blocks are placed into the buffer cache. This may result in aging out of other blocks that may be reread by other processes. To avoid this you can use the parameter &lt;Parameter:SORT_DIRECT_WRITES&gt; which does not place sort blocks into the buffer cache.</p>
<p>Filter</p>
<p>Has a number of different meanings used to indicate partition elimination may also indicate an actual filter step where one row source is filtering another functions such as min may introduce filter steps into query plans</p>
<p>In this example there are 2 filter steps. The first is effectively like a NL except that it stops when it gets something that it doesn&#8217;t like (i.e. a bounded NL). This is there because of the not in. The second is filtering out the min value:</p>
<p>SQL&gt; explain plan for select * from emp<br />
     where empno not in (select min(empno)<br />
     from big_emp group by empno);</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE]  Cost=1<br />
  FILTER     **** This is like a bounded nested loops<br />
    TABLE ACCESS FULL EMP [ANALYZED]<br />
     FILTER   **** This filter is introduced by the min<br />
        SORT GROUP BY NOSORT<br />
          INDEX FULL SCAN BE_IX</p>
<p>This example is also interesting in that it has a NOSORT function. The group by does not need to sort because the index row source is already pre sorted.</p>
<p>Views</p>
<p>When a view cannot be merged into the main query you will often see a projection view operation. This indicates that the &#8216;view&#8217; will be selected from directly as opposed to being broken down into joins on the base tables. A number of constructs make a view non mergeable. Inline views are also non mergeable.</p>
<p>In the following example the select contains an inline view which cannot be merged:</p>
<p>SQL&gt; explain plan for<br />
select ename,tot<br />
from emp,<br />
    (select empno,sum(empno) tot from big_emp group by empno) tmp<br />
where emp.empno = tmp.empno;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE]<br />
  HASH JOIN<br />
    TABLE ACCESS FULL EMP [ANALYZED]<br />
    VIEW<br />
      SORT GROUP BY<br />
        INDEX FULL SCAN BE_IX</p>
<p>In this case the inline view tmp which contains an aggregate function cannot be merged into the main query. The explain plan shows this as a view step.</p>
<p>Partition Views</p>
<p>Allows a large table to be broken up into a number of smaller partitions which can be queried much more quickly than the table as a whole a union all view is built over the top to provide the original functionality Check constraints or where clauses provide partition elimination capabilities</p>
<p>SQL&gt; explain plan for<br />
select /*+ use_nl(p1,kbwyv1) ordered */  sum(prc_pd)<br />
from parent1 p1,  kbwyv1<br />
where p1.class = 22<br />
and   kbwyv1.bitm_numb = p1.bitm_numb<br />
and   kbwyv1.year = 1997<br />
and   kbwyv1.week between 32 and 33 ;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT   [FIRST_ROWS] Cost=1780<br />
  SORT AGGREGATE<br />
    NESTED LOOPS   [:Q65001] Ct=1780 Cd=40 Bt=3120<br />
      TABLE ACCESS FULL PARENT1 [:Q65000] [AN] Ct=20 Cd=40 Bt=1040<br />
      VIEW  KBWYV1 [:Q65001]<br />
        UNION-ALL PARTITION  [:Q65001]<br />
          FILTER   [:Q64000]<br />
            TABLE ACCESS FULL KBWYT1 [AN] Ct=11 Cd=2000 Bt=104000<br />
          TABLE ACCESS FULL KBWYT2 [AN] Ct=11 Cd=2000 Bt=104000<br />
          TABLE ACCESS FULL KBWYT3 [AN] Ct=11 Cd=2000 Bt=104000<br />
          FILTER   [:Q61000]<br />
            TABLE ACCESS FULL KBWYT4 [AN] Ct=11 Cd=2000 Bt=104000</p>
<p>KBWYV1 is a view on 4 tables KBWYT1-4. KBWYT1-4 contain rows for week 31-34 respectively and are maintained by check constraints. This query should only return rows from partions 2 &amp; 3. The filter operation indicates this. Partitions 1 &amp; 4 are eliminated at execution time. The view line indicates that the view is not merged. The union-all partion information indicates that we have recognised this as a partition view. Note that the tables can be accessed in parallel.</p>
<p>Remote Queries</p>
<p>Only shows remote in the OPERATION column OTHER column shows query executed on remote node OTHER_NODE shows where it is executed Different operational characteristics for RBO &amp; CBO</p>
<p>RBO &#8211; Drags everything across the link and joins locally<br />
CBO &#8211; Uses cost estimates to determine whether to execute remotely or locally</p>
<p>SQL&gt;  explain plan for<br />
select *<br />
from dept@loop_link;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
SELECT STATEMENT REMOTE  [CHOOSE] Cost=1<br />
  TABLE ACCESS FULL DEPT [SJD.WORLD] [ANALYZED]</p>
<p>In this case the whole query has been sent to the remote site. The other column shows nothing.</p>
<p>SQL&gt; explain plan for<br />
select a.dname,avg(b.sal),max(b.sal)<br />
from dept@loop_link a, emp b<br />
where a.deptno=b.deptno<br />
group by a.dname<br />
order by max(b.sal),avg(b.sal) desc;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT   [CHOOSE] Cost=20<br />
  SORT ORDER BY  [:Q137003] [PARALLEL_TO_SERIAL]<br />
    SORT GROUP BY  [:Q137002] [PARALLEL_TO_PARALLEL]<br />
      NESTED LOOPS   [:Q137001] [PARALLEL_TO_PARALLEL]<br />
        REMOTE   [:Q137000] [PARALLEL_FROM_SERIAL]<br />
        TABLE ACCESS FULL EMP [:Q137001] [ANALYZED]<br />
        [PARALLEL_COMBINED_WITH_PARENT]</p>
<p>Bind Variables</p>
<p>Bind variables are recommended in most cases because they promote sharing of sql code<br />
At parse time the parser has NO IDEA what the bind variable contains. With RBO this makes no difference but with CBO, which relies on accurate statistics to produce plans, this can be a problem.</p>
<p>Defining bind variables in sqlplus:</p>
<p>variable x varchar2(18);<br />
assigning values:<br />
begin<br />
 <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_mad.gif' alt=':x' class='wp-smiley' />  := &#8216;hello&#8217;;<br />
end;<br />
/</p>
<p>SQL&gt; explain plan for<br />
select *<br />
from dept<br />
where rowid = &#8216;:x&#8217;;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
  TABLE ACCESS BY ROWID DEPT [ANALYZED]</p>
<p>Parallel Query</p>
<p>Main indicators that a query is using PQO:</p>
<ul>
<li>[:Q1000004] entries in the explain plan</li>
<li>Checkout the other column for details of what the slaves are executing</li>
<li>v$pq_slave will show any parallel activity</li>
</ul>
<p>Columns to look in for information</p>
<ul>
<li>other &#8211; contains the query passed to the slaves</li>
<li>other_tag &#8211; describes the contents of other</li>
<li>object_node &#8211; indicates order of pqo slaves</li>
</ul>
<p>Parallel Query operates on a producer/consumer basis. When you specify parallel degree 4 oracle tries to allocate 4 producer slaves and 4 consumer slaves. The producers can feed any of the consumers. If there are only 2 slaves available then we use these. If there is only 1 slave available then we go serial If there are none available then we use serial. If parallel_min_percent is set then we error ora 12827 instead of using a lower number of slaves or going serial</p>
<p>Consumer processes typically perform a sorting function. If there is no requirement for the data to be sorted then the consumer slaves are not produced and we end up with the number of slaves used matching the degree of parallelism as opposed to being 2x the degree.</p>
<p>Parallel Terms</p>
<table border="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td width="50%" valign="top">PARALLEL_FROM_SERIAL</td>
<td width="50%" valign="top">This means that source of the data is serial but it is passed to a parallel consumer</td>
</tr>
<tr>
<td width="50%" valign="top">PARALLEL_TO_PARALLEL</td>
<td width="50%" valign="top">Both the consumer and the producer are  parallel</td>
</tr>
<tr>
<td width="50%" valign="top">PARALLEL_COMBINED_WITH_PARENT</td>
<td width="50%" valign="top">This operation has been combined with the parent operator. For example in a sort merge join the sort operations would be shown as PARALLEL_COMBINED_WITH_PARENT because the sort and the merge are handled as 1 operation.</td>
</tr>
<tr>
<td width="50%" valign="top">PARALELL_TO_SERIAL</td>
<td width="50%" valign="top">The source of the data is parallel but it is passed to a serial consumer. This typically will happen at the top of the explain plan but could occur anywhere</td>
</tr>
</tbody>
</table>
<p>Examples of parallel queries</p>
<p>Assumptions</p>
<p>OPTIMIZER_MODE = CHOOSE<br />
DEPT is small compared to EMP<br />
DEPT has an index (DEPT_INDX) on deptno column</p>
<p>Three examples are presented</p>
<p>Query #1:  Serial<br />
Query #2:  Parallel<br />
Query #3:  Parallel, with forced optimization to RULE and forced usage of DEPT_INDX</p>
<p>Sample Query #1 (Serial)</p>
<p>select A.dname, avg(B.sal), max(B.sal)<br />
from  dept A, emp B<br />
where A.deptno = B.deptno<br />
group by A.dname<br />
order by max(B.sal), avg(B.sal) desc;</p>
<p>Execution Plan #1 (Serial)</p>
<p>OBJECT_NAME                      OBJECT_NODE OTHER<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-  &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;-<br />
SELECT STATEMENT<br />
 SORT ORDER BY<br />
   SORT GROUP BY<br />
     MERGE JOIN<br />
       SORT JOIN<br />
         TABLE ACCESS FULL emp<br />
       SORT JOIN<br />
         TABLE ACCESS FULL dept</p>
<p>Notice that the object_node and other columns are empty</p>
<p>Sample Query #2 (Query #1 with parallel hints)</p>
<p>select <strong>/*+ parallel(B,4) parallel(A,4) */</strong><br />
A.dname, avg(B.sal), max(B.sal)<br />
from  dept A, emp B<br />
where A.deptno = B.deptno<br />
group by A.dname<br />
order by max(B.sal), avg(B.sal) desc;</p>
<p>Execution Plan #2  (Parallel)</p>
<p>OBJECT_NAME                      OBJECT_NODE OTHER<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-  &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;-<br />
SELECT STATEMENT      Cost = ??<br />
 SORT ORDER BY                   :Q55004     **[7]**<br />
   SORT GROUP BY                 :Q55003     **[6]**<br />
     MERGE JOIN                  :Q55002     **[5]**<br />
       SORT JOIN                 :Q55002     **[4]**<br />
         TABLE ACCESS FULL emp   :Q55001     **[2]**<br />
       SORT JOIN                 :Q55002     **[3]**<br />
         TABLE ACCESS FULL dept  :Q55000     **[1]**</p>
<p>Execution Plan #2  &#8212; OTHER column</p>
<p>**[1]**  (:Q55000) &#8220;PARALLEL_FROM_SERIAL&#8221;</p>
<p>Serial execution of SELECT DEPTNO, DNAME FROM DEPT</p>
<p>**[2]**  (:Q55001) &#8220;PARALLEL_TO_PARALLEL&#8221;</p>
<p>        SELECT /*+ ROWID(A1)*/<br />
        A1.&#8221;DEPTNO&#8221; C0, A1.&#8221;SAL&#8221; C1<br />
        FROM &#8220;EMP&#8221; A1<br />
        WHERE ROWID BETWEEN :1 AND :2</p>
<p>**[3]**  (:Q55002) &#8220;PARALLEL_COMBINED_WITH_PARENT&#8221;<br />
**[4]**  (:Q55002) &#8220;PARALLEL_COMBINED_WITH_PARENT&#8221;<br />
**[5]**  (:Q55002) &#8220;PARALLEL_TO_PARALLEL&#8221;</p>
<p>        SELECT /*+ ORDERED USE_MERGE(A2)*/<br />
        A2.C1 C0, A1.C1 C1<br />
        FROM :Q55001 A1,:Q55000 A2<br />
        WHERE A1.C0=A2.C0</p>
<p>**[6]**  (:Q55003) &#8220;PARALLEL_TO_PARALLEL&#8221;</p>
<p>        SELECT MAX(A1.C1) C0, AVG(A1.C1) C1, A1.C0 C2<br />
        FROM :Q55002 A1<br />
        GROUP BY A1.C0</p>
<p>**[7]**  (:Q55004) &#8220;PARALLEL_FROM_SERIAL&#8221;</p>
<p>        SELECT A1.C0 C0, A1.C1 C1, A1.C2 C2<br />
        FROM :Q55003 A1<br />
        ORDER BY A1.CO, A1.C1 DESC</p>
<p>Sample Query #3 (Query #2 with fudged hints)</p>
<p>select /*+ index(A dept_indx) <strong>parallel(B,4) parallel(A,4)</strong> */<br />
      A.dname, avg(B.sal), max(B.sal)<br />
from  dept A, emp B<br />
where A.deptno = B.deptno<br />
group by A.dname<br />
order by max(B.sal), avg(B.sal) desc;</p>
<p>Execution Plan #3  (Parallel)</p>
<p>OBJECT_NAME                         OBJECT_NODE OTHER<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;-<br />
SELECT STATEMENT          Cost = ??<br />
 SORT ORDER BY                      :Q58002     **[6]**<br />
   SORT GROUP BY                    :Q58001     **[5]**<br />
     NESTED LOOPS JOIN              :Q58000     **[4]**<br />
       TABLE ACCESS FULL emp        :Q58000     **[3]**<br />
       TABLE ACCESS BY ROWID dept   :Q58000     **[2]**<br />
         INDEX RANGE SCAN dept_indx :Q58000     **[1]**</p>
<p>Execution Plan #3  &#8212; OTHER column</p>
<p>**[1]**  (:Q58000) &#8220;PARALLEL_COMBINED_WITH_PARENT&#8221;<br />
**[2]**  (:Q58000) &#8220;PARALLEL_COMBINED_WITH_PARENT&#8221;<br />
**[3]**  (:Q58000) &#8220;PARALLEL_COMBINED_WITH_PARENT&#8221;<br />
**[4]**  (:Q58000) &#8220;PARALLEL_TO_PARALLEL&#8221;</p>
<p>        SELECT /*+ ORDERED USE_NL(A2) INDEX(A2) */<br />
        A2.&#8221;DNAME&#8221; C0, A1.C0 C1<br />
        FROM<br />
          (SELECT /*+ ROWID(A3) */<br />
           A3.&#8221;SAL&#8221; CO, A3.&#8221;DEPTNO&#8221; C1<br />
           FROM &#8220;EMP&#8221; A3<br />
           WHERE ROWID BETWEEN :1 AND :2) A1,<br />
          &#8220;DEPT&#8221; A2<br />
        WHERE A2.&#8221;DEPTNO&#8221; = A1.C1</p>
<p>**[5]**  (:Q58001) &#8220;PARALLEL_TO_PARALLEL&#8221;</p>
<p>        SELECT MAX(A1.C1) C0, AVG(A1.C1) C1, A1.C0 C2<br />
        FROM :Q58000 A1<br />
        GROUP BY A1.C0</p>
<p>**[6]**  (:Q58002) &#8220;PARALLEL_TO_SERIAL&#8221;</p>
<p>        SELECT A1.C0 C0, A1.C1 C1, A1.C2 C2<br />
        FROM :Q58001 A1<br />
        ORDER BY A1.C0, A1.C1 DESC</p>
<p>How to obtain explain plans</p>
<p>Explain plan for</p>
<p>Main advantage is that it does not actually run the query &#8211; just parses the sql. This means that it executes quickly. In the early stages of tuning explain plan gives you an idea of the potential performance of your query without actually running it. You can then make a judgement as to any modifications you may choose to make.</p>
<p>Autotrace</p>
<p>Autotrace can be configured to run the sql &amp; gives a plan  and statistics afterwards or just give you an explain plan without execu</p>
<table border="0" cellspacing="0" cellpadding="4" width="570">
<tbody>
<tr>
<td width="100" height="35" valign="top">
<p align="left"><a href="history.back()"><img src="http://enginozer.wordpress.com/img/zurueck.gif" border="0" alt="Zurück" width="76" height="19" /></a></p>
</td>
<th height="35" valign="top">
<p align="left"><img src="http://enginozer.wordpress.com/img/bullet-gruen.gif" alt="" width="15" height="10" />  Interpreting Explain Plan  <img src="http://enginozer.wordpress.com/img/bullet-gruen.gif" alt="" width="15" height="10" /></p>
</th>
</tr>
<tr>
<td colspan="2" valign="top">What&#8217;s an explain plan?</p>
<p>An explain plan is a representation of the access path that is taken when a query is executed within Oracle.</p>
<p>Query processing can be divided into 7 phases:</p>
<table border="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td width="25%" valign="top">[1] Syntactic</td>
<td width="75%" valign="top">Checks the syntax of the query</td>
</tr>
<tr>
<td width="25%" valign="top">[2] Semantic</td>
<td width="75%" valign="top">Checks that all objects exist and are accessible</td>
</tr>
<tr>
<td width="25%" valign="top">[3] View Merging</td>
<td width="75%" valign="top">Rewrites query as join on base tables as opposed to using views</td>
</tr>
<tr>
<td width="25%" valign="top">[4] Statement<br />
     Transformation</td>
<td width="75%" valign="top">Rewrites query transforming some complex constructs into simpler ones where appropriate (e.g. subquery merging, in/or transformation)</td>
</tr>
<tr>
<td width="25%" valign="top">[5] Optimization</td>
<td width="75%" valign="top">Determines the optimal access path for the query to take. With the Rule Based Optimizer (RBO) it uses a set of heuristics to determine access path. With the Cost Based Optimizer (CBO) we use statistics to analyze the relative costs of accessing objects.</td>
</tr>
<tr>
<td width="25%" valign="top">[6] QEP Generation</td>
<td width="75%" valign="top">QEP = Query Evaluation Plan</td>
</tr>
<tr>
<td width="25%" valign="top">[7] QEP Execution</td>
<td width="75%" valign="top">QEP = Query Evaluation Plan</td>
</tr>
</tbody>
</table>
<p>Steps [1]-[6] are handled by the parser. Step [7] is the execution of the statement.</p>
<p>The explain plan is produced by the parser. Once the access path has been decided upon it is stored in the library cache together with the statement itself. We store queries in the library cache based upon a hashed representation  of that query. When looking for a statement in the library cache, we first apply a hashing algorithm to the statement and then we look for this hash value in the library cache. This access path will be used until the query is reparsed.</p>
<p>Terminology</p>
<table border="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td width="25%">Row Source</td>
<td width="75%">A set of rows used in a query may be a select from a base object or the result set returned by joining 2 earlier row sources</td>
</tr>
<tr>
<td width="25%">Predicate</td>
<td width="75%">where clause of a query</td>
</tr>
<tr>
<td width="25%">Tuples</td>
<td width="75%">rows</td>
</tr>
<tr>
<td width="25%">Driving Table</td>
<td width="75%">This is the row source that we use to seed the query. If this returns a lot of rows then this can have a negative affect on all subsequent operations</td>
</tr>
<tr>
<td width="25%">Probed Table</td>
<td width="75%">This is the object we lookup data in after we have retrieved relevant key data from the driving table.</td>
</tr>
</tbody>
</table>
<p>How does Oracle access data?</p>
<p>At the physical level Oracle reads blocks of data. The smallest amount of data read is a single Oracle block, the largest is constrained by operating system limits (and multiblock i/o). Logically Oracle finds the data to read by using the following methods:</p>
<ul>
<li>Full Table Scan (FTS)</li>
<li>Index Lookup (unique &amp; non-unique)</li>
<li>Rowid</li>
</ul>
<p>Explain plan Hierarchy</p>
<p>Simple explain plan:</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT     [CHOOSE] Cost=1234<br />
  TABLE ACCESS FULL LARGE [:Q65001] [ANALYZED]</p>
<p>The rightmost uppermost operation of an explain plan is the first thing that the explain plan will execute. In this case TABLE ACCESS FULL LARGE is the first operation. This statement means we are doing a full table scan of table LARGE. When this operation completes then the resultant row source is passed up to the<br />
next level of the query for processing. In this case it is the SELECT STATEMENT which is the top of the query.</p>
<p>[CHOOSE] is an indication of the optimizer_goal for the query. This DOES NOT necessarily indicate that plan has actually used this goal. The only way to confirm this is to check the<br />
cost= part of the explain plan as well. For example the following query indicates that the CBO has been used because there is a cost in the cost field:</p>
<p>SELECT STATEMENT     [CHOOSE] Cost=1234</p>
<p>However the explain plan below indicates the use of the RBO because the cost field is blank:</p>
<p>SELECT STATEMENT     [CHOOSE] Cost=</p>
<p>The cost field is a comparative cost that is used internally to determine the best cost for particular plans. The costs of different statements are not really directly comparable.</p>
<p>[:Q65001] indicates that this particular part of the query is being executed in parallel. This number indicates that the operation will be processed by a parallel query slave as opposed to being executed serially.</p>
<p>[ANALYZED] indicates that the object in question has been analyzed and there are currently statistics available for the CBO to use. There is no indication of the &#8216;level&#8217; of analysis done.</p>
<p>Access Methods in detail</p>
<p>Full Table Scan (FTS)</p>
<p>In a FTS operation, the whole table is read up to the high water mark (HWM). The HWM marks the last block in the table that has ever had data written to it. If you have deleted all the rows then you will still read up to the HWM. Truncate resets the HWM back to the start of the table. FTS uses multiblock i/o to read the blocks from disk. Multiblock i/o is controlled by the parameter &lt;PARAM:db_block_multi_block_read_count&gt;.</p>
<p>This defaults to:</p>
<p>db_block_buffers / ( (PROCESSES+3) / 4 )</p>
<p>Maximum values are OS dependant</p>
<p>Buffers from FTS operations are placed on the Least Recently Used (LRU) end of the buffer cache so will be quickly aged out. FTS is not recommended for large tables unless you are reading &gt;5-10% of it (or so) or you intend to run in parallel.</p>
<p>Example FTS explain plan:</p>
<p>SQL&gt; explain plan for select * from dual;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT     [CHOOSE] Cost=<br />
  TABLE ACCESS FULL DUAL</p>
<p>Index lookup</p>
<p>Data is accessed by looking up key values in an index and returning rowids. A rowid uniquely identifies an individual row in a particular data block. This block is read via single block i/o.</p>
<p>In this example an index is used to find the relevant row(s) and then the table is accessed to lookup the ename column (which is not included in the index):</p>
<p>SQL&gt; explain plan for<br />
select empno,ename from emp where empno=10;<br />
Query Plan</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
TABLE ACCESS BY ROWID EMP [ANALYZED]<br />
    INDEX UNIQUE SCAN EMP_I1</p>
<p>Notice the &#8216;TABLE ACCESS BY ROWID&#8217; section. This indicates that the table data is not being accessed via a FTS operation but rather by a rowid lookup. In this case the rowid has been produced by looking up values in the index first. The index is being accessed by an &#8216;INDEX UNIQUE SCAN&#8217; operation. This is explained below. The index name in this case is EMP_I1. If all the required data resides in the index then a table lookup may be unnecessary and all you will see is an index access with no table access.</p>
<p>In the following example all the columns (empno) are in the index. Notice that no table access takes place:</p>
<p>SQL&gt; explain plan for<br />
select empno from emp where empno=10;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
  INDEX UNIQUE SCAN EMP_I1</p>
<p>Indexes are presorted so sorting may be unecessary if the sort order required is the same as the index.</p>
<p>SQL&gt; explain plan for select empno,ename from emp<br />
where empno &gt; 7876 order by empno;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
SELECT STATEMENT   [CHOOSE] Cost=1<br />
TABLE ACCESS BY ROWID EMP [ANALYZED]<br />
  INDEX RANGE SCAN EMP_I1 [ANALYZED]</p>
<p>In this case the index is sorted so ther rows will be returned in the order of the index hence a sort is unecessary.</p>
<p>SQL&gt; explain plan for<br />
select /*+ Full(emp) */ empno,ename from emp<br />
where empno&gt; 7876 order by empno;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
SELECT STATEMENT   [CHOOSE] Cost=9<br />
  SORT ORDER BY<br />
    TABLE ACCESS FULL EMP [ANALYZED]  Cost=1 Card=2 Bytes=66</p>
<p>Because we have forced a FTS the data is unsorted and so we must sort the data<br />
after it has been retrieved.</p>
<p>There are 4 methods of index lookup:</p>
<ul>
<li>index unique scan</li>
<li>index range scan</li>
<li>index full scan</li>
<li>index fast full scan</li>
</ul>
<p>Index unique scan</p>
<p>Method for looking up a single key value via a unique index. Always returns a single value You must supply AT LEAST the leading column of the index to access data via the index, However this may return &gt; 1 row as the uniqueness will not be guaranteed.</p>
<p>SQL&gt; explain plan for<br />
select empno,ename from emp where empno=10;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
TABLE ACCESS BY ROWID EMP [ANALYZED]<br />
    INDEX UNIQUE SCAN EMP_I1</p>
<p>Index range scan</p>
<p>Method for accessing multiple column values You must supply AT LEAST the leading column of the index to access data via the index Can be used for range operations (e.g. &gt; &lt; &lt;&gt; &gt;= &lt;= between)</p>
<p>SQL&gt; explain plan for select empno,ename from emp<br />
where empno &gt; 7876 order by empno;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
SELECT STATEMENT   [CHOOSE] Cost=1<br />
TABLE ACCESS BY ROWID EMP [ANALYZED]<br />
  INDEX RANGE SCAN EMP_I1 [ANALYZED]</p>
<p>A non-unique index may return multiple values for the predicate col1 = 5 and will use an index range scan</p>
<p>SQL&gt; explain plan for select mgr from emp where mgr = 5</p>
<p>Query plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
  INDEX RANGE SCAN EMP_I2 [ANALYZED]</p>
<p>Index Full Scan</p>
<p>In certain circumstances it is possible for the whole index to be scanned as opposed to a range scan (i.e. where no constraining predicates are provided for a table). Full index scans are  only available in the CBO as otherwise we are unable to determine whether a full scan would be a good idea or not. We choose an index Full Scan when we have statistics that indicate that it is going to be more efficient than a Full table scan and a sort.</p>
<p>For example we may do a Full index scan when we do an unbounded scan of an index and want the data to be ordered in the index order. The optimizer may decide that selecting all the information from the index and not sorting is more efficient than doing a FTS or a Fast Full Index Scan and then sorting.</p>
<p>An Index full scan will perform single block i/o&#8217;s and so it may prove to be inefficient. Index BE_IX is a concatenated index on big_emp (empno,ename)</p>
<p>SQL&gt; explain plan for select empno,ename<br />
     from big_emp order by empno,ename;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT   [CHOOSE] Cost=26<br />
  INDEX FULL SCAN BE_IX [ANALYZED]</p>
<p>Index Fast Full Scan</p>
<p>Scans all the block in the index Rows are not returned in sorted order Introduced in 7.3 and requires V733_PLANS_ENABLED=TRUE and CBO may be hinted using INDEX_FFS hint uses multiblock i/o can be executed in parallel can be used to access second column of concatenated indexes. This is because we are selecting all of the index.</p>
<p>Note that INDEX FAST FULL SCAN is the mechinism behind fast index create and recreate. Index BE_IX is a concatenated index on big_emp (empno,ename)</p>
<p>SQL&gt; explain plan for select empno,ename from big_emp;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT   [CHOOSE] Cost=1<br />
  INDEX FAST FULL SCAN BE_IX [ANALYZED]</p>
<p>Selecting the 2nd column of concatenated index:</p>
<p>SQL&gt; explain plan for select ename from big_emp;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT   [CHOOSE] Cost=1<br />
  INDEX FAST FULL SCAN BE_IX [ANALYZED]</p>
<p>Rowid</p>
<p>This is the quickest access method available Oracle simply retrieves the block specified and extracts the rows it is interested in. Most frequently seen in explain plans as Table access by Rowid</p>
<p>SQL&gt; explain plan for select * from dept where rowid = &#8216;:x&#8217;;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
TABLE ACCESS BY ROWID DEPT [ANALYZED]</p>
<p>Table is accessed by rowid following index lookup:</p>
<p>SQL&gt; explain plan for<br />
select empno,ename from emp where empno=10;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
TABLE ACCESS BY ROWID EMP [ANALYZED]<br />
    INDEX UNIQUE SCAN EMP_I1</p>
<p>Joins</p>
<p>A Join is a predicate that attempts to combine 2 row sources We only ever join 2 row sources together Join steps are always performed serially even though underlying row sources may have been accessed in parallel. Join order &#8211; order in which joins are performed</p>
<p>The join order makes a significant difference to the way in which the query is executed. By accessing particular row sources first, certain predicates may be satisfied that are not satisfied by with other join orders. This may prevent certain access paths from being taken.</p>
<p>Suppose there is a concatenated index on A(a.col1,a.col2). Note that a.col1 is the leading column. Consider the following query:</p>
<p>select A.col4<br />
from   A,B,C<br />
where  B.col3 = 10<br />
and    A.col1 = B.col1<br />
and    A.col2 = C.col2<br />
and    C.col3 = 5</p>
<p>We could represent the joins present in the query using the following schematic:</p>
<p>  B     &lt;&#8212;&gt; A &lt;&#8212;&gt;    C<br />
col3=10                col3=5</p>
<p>There are really only 2 ways we can drive the query: via B.col3 or C.col3. We would have to do a Full scan of A to be able to drive off it. This is unlikely to be efficient with large tables;</p>
<p>If we drive off table B, using predicate B.col3=10 (as a filter or lookup key) then we will retrieve the value for B.col1 and join to A.col1. Because we have now filled the leading column of the concatenated index on table A we can use this index to give us values for A.col2 and join to A.</p>
<p>However if we drive of table c, then we only get a value for a.col2 and since this is a trailing column of a concatenated index and the leading column has not been supplied at this point, we cannot use the index on a to lookup the data.</p>
<p>So it is likely that the best join order will be B A C. The CBO will obviously use costs to establish whether the individual access paths are a good idea or not.</p>
<p>If the CBO does not choose this join order then we can hint it by changing the from<br />
clause to read:</p>
<p>from B,A,C</p>
<p>and using the /*+ ordered */ hint. The resultant query would be:</p>
<p>select /*+ ordered */ A.col4<br />
from   B,A,C<br />
where  B.col3 = 10<br />
and    A.col1 = B.col1<br />
and    A.col2 = C.col2<br />
and    C.col3 = 5</p>
<p>Join Types</p>
<ul>
<li>Sort Merge Join (SMJ)</li>
<li>Nested Loops (NL)</li>
<li>Hash Join</li>
</ul>
<p>Sort Merge Join</p>
<p>Rows are produced by Row Source 1 and are then sorted Rows from Row Source 2 are then produced and sorted by the same sort key as Row Source 1. Row Source 1 and 2 are NOT accessed concurrently Sorted rows from both sides are then merged together (joined)</p>
<p>                   MERGE<br />
                 /      \<br />
            SORT        SORT<br />
             |             |<br />
        Row Source 1  Row Source 2</p>
<p>If the row sources are already (known to be) sorted then the sort operation is unecessary as long as both &#8217;sides&#8217; are sorted using the same key. Presorted row sources include indexed columns and row sources that have already been sorted in earlier steps. Although the merge of the 2 row sources is handled serially, the row sources could be accessed in parallel.</p>
<p>SQL&gt; explain plan for<br />
select /*+ ordered */ e.deptno,d.deptno<br />
from emp e,dept d<br />
where e.deptno = d.deptno<br />
order by e.deptno,d.deptno;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
SELECT STATEMENT [CHOOSE] Cost=17<br />
  MERGE JOIN<br />
    SORT JOIN<br />
      TABLE ACCESS FULL EMP [ANALYZED]<br />
    SORT JOIN<br />
      TABLE ACCESS FULL DEPT [ANALYZED]</p>
<p>Sorting is an expensive operation, especially with large tables. Because of this, SMJ is often not a particularly efficient join method.</p>
<p>Nested Loops</p>
<p>First we return all the rows from row source 1 Then we probe row source 2 once for each row returned from row source 1</p>
<p>Row source 1<br />
~~~~~~~~~~~~<br />
Row 1 &#8212;&#8212;&#8212;&#8212;&#8211;       &#8212; Probe -&gt;       Row source 2<br />
Row 2 &#8212;&#8212;&#8212;&#8212;&#8211;       &#8212; Probe -&gt;       Row source 2<br />
Row 3 &#8212;&#8212;&#8212;&#8212;&#8211;       &#8212; Probe -&gt;       Row source 2</p>
<p>Row source 1 is known as the outer table<br />
Row source 2 is known as the inner table</p>
<p>Accessing row source 2 is known a probing the inner table For nested loops to be efficient it is important that the first row source returns as few rows as possible as this directly controls the number of probes of the second row source. Also it helps if the access method for row source 2 is efficient as this operation is being repeated once for every row returned by row source 1.</p>
<p>SQL&gt; explain plan for<br />
select a.dname,b.sql<br />
from dept a,emp b<br />
where a.deptno = b.deptno;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
SELECT STATEMENT [CHOOSE] Cost=5<br />
  NESTED LOOPS<br />
    TABLE ACCESS FULL DEPT [ANALYZED]<br />
    TABLE ACCESS FULL EMP [ANALYZED]</p>
<p>Hash Join</p>
<p>New join type introduced in 7.3 More efficient in theory than NL &amp; SMJ Only accessible via the CBO Smallest row source is chosen and used to build a hash table and a bitmap The second row source is hashed and checked against the hash table looking for joins. The bitmap is used as a quick lookup to check if rows are in the hash table and are especially useful when the hash table is too large to fit in memory.</p>
<p>SQL&gt; explain plan for<br />
select /*+ use_hash(emp) */ empno<br />
from emp,dept<br />
where emp.deptno = dept.deptno;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
SELECT STATEMENT  [CHOOSE] Cost=3<br />
  HASH JOIN<br />
    TABLE ACCESS FULL DEPT<br />
    TABLE ACCESS FULL EMP</p>
<p>Hash joins are enabled by the parameter HASH_JOIN_ENABLED=TRUE in the init.ora or session. TRUE is the default in 7.3</p>
<p>Cartesian Product</p>
<p>A Cartesian Product is done where they are no join conditions between 2 row sources and there is no alternative method of accessing the data Not really a join as such as there is no join! Typically this is caused by a coding mistake where a join has been left out. It can be useful in some circumstances &#8211; Star joins uses cartesian products.</p>
<p>Notice that there is no join between the 2 tables:</p>
<p>SQL&gt; explain plan for<br />
select emp.deptno,dept,deptno<br />
from emp,dept</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SLECT STATEMENT [CHOOSE] Cost=5<br />
  MERGE JOIN CARTESIAN<br />
    TABLE ACCESS FULL DEPT<br />
    SORT JOIN<br />
      TABLE ACCESS FULL EMP</p>
<p>The CARTESIAN keyword indicate that we are doing a cartesian product.</p>
<p>Operations</p>
<p>Operations that show up in explain plans</p>
<ul>
<li>sort</li>
<li>filter</li>
<li>view</li>
</ul>
<p>Sorts</p>
<p>There are a number of different operations that promote sorts</p>
<ul>
<li>order by clauses</li>
<li>group by</li>
<li>sort merge join</li>
</ul>
<p>Note that if the row source is already appropriately sorted then no sorting is required. This is now indicated in 7.3:</p>
<p>SORT GROUP BY NOSORT<br />
     INDEX FULL SCAN &#8230;..</p>
<p>In this case the group by operation simply groups the rows it does not do the sort operation as this has already been completed.</p>
<p>Sorts are expensive operations especially on large tables where the rows do not fit in memory and spill to disk. By default sort blocks are placed into the buffer cache. This may result in aging out of other blocks that may be reread by other processes. To avoid this you can use the parameter &lt;Parameter:SORT_DIRECT_WRITES&gt; which does not place sort blocks into the buffer cache.</p>
<p>Filter</p>
<p>Has a number of different meanings used to indicate partition elimination may also indicate an actual filter step where one row source is filtering another functions such as min may introduce filter steps into query plans</p>
<p>In this example there are 2 filter steps. The first is effectively like a NL except that it stops when it gets something that it doesn&#8217;t like (i.e. a bounded NL). This is there because of the not in. The second is filtering out the min value:</p>
<p>SQL&gt; explain plan for select * from emp<br />
     where empno not in (select min(empno)<br />
     from big_emp group by empno);</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE]  Cost=1<br />
  FILTER     **** This is like a bounded nested loops<br />
    TABLE ACCESS FULL EMP [ANALYZED]<br />
     FILTER   **** This filter is introduced by the min<br />
        SORT GROUP BY NOSORT<br />
          INDEX FULL SCAN BE_IX</p>
<p>This example is also interesting in that it has a NOSORT function. The group by does not need to sort because the index row source is already pre sorted.</p>
<p>Views</p>
<p>When a view cannot be merged into the main query you will often see a projection view operation. This indicates that the &#8216;view&#8217; will be selected from directly as opposed to being broken down into joins on the base tables. A number of constructs make a view non mergeable. Inline views are also non mergeable.</p>
<p>In the following example the select contains an inline view which cannot be merged:</p>
<p>SQL&gt; explain plan for<br />
select ename,tot<br />
from emp,<br />
    (select empno,sum(empno) tot from big_emp group by empno) tmp<br />
where emp.empno = tmp.empno;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE]<br />
  HASH JOIN<br />
    TABLE ACCESS FULL EMP [ANALYZED]<br />
    VIEW<br />
      SORT GROUP BY<br />
        INDEX FULL SCAN BE_IX</p>
<p>In this case the inline view tmp which contains an aggregate function cannot be merged into the main query. The explain plan shows this as a view step.</p>
<p>Partition Views</p>
<p>Allows a large table to be broken up into a number of smaller partitions which can be queried much more quickly than the table as a whole a union all view is built over the top to provide the original functionality Check constraints or where clauses provide partition elimination capabilities</p>
<p>SQL&gt; explain plan for<br />
select /*+ use_nl(p1,kbwyv1) ordered */  sum(prc_pd)<br />
from parent1 p1,  kbwyv1<br />
where p1.class = 22<br />
and   kbwyv1.bitm_numb = p1.bitm_numb<br />
and   kbwyv1.year = 1997<br />
and   kbwyv1.week between 32 and 33 ;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT   [FIRST_ROWS] Cost=1780<br />
  SORT AGGREGATE<br />
    NESTED LOOPS   [:Q65001] Ct=1780 Cd=40 Bt=3120<br />
      TABLE ACCESS FULL PARENT1 [:Q65000] [AN] Ct=20 Cd=40 Bt=1040<br />
      VIEW  KBWYV1 [:Q65001]<br />
        UNION-ALL PARTITION  [:Q65001]<br />
          FILTER   [:Q64000]<br />
            TABLE ACCESS FULL KBWYT1 [AN] Ct=11 Cd=2000 Bt=104000<br />
          TABLE ACCESS FULL KBWYT2 [AN] Ct=11 Cd=2000 Bt=104000<br />
          TABLE ACCESS FULL KBWYT3 [AN] Ct=11 Cd=2000 Bt=104000<br />
          FILTER   [:Q61000]<br />
            TABLE ACCESS FULL KBWYT4 [AN] Ct=11 Cd=2000 Bt=104000</p>
<p>KBWYV1 is a view on 4 tables KBWYT1-4. KBWYT1-4 contain rows for week 31-34 respectively and are maintained by check constraints. This query should only return rows from partions 2 &amp; 3. The filter operation indicates this. Partitions 1 &amp; 4 are eliminated at execution time. The view line indicates that the view is not merged. The union-all partion information indicates that we have recognised this as a partition view. Note that the tables can be accessed in parallel.</p>
<p>Remote Queries</p>
<p>Only shows remote in the OPERATION column OTHER column shows query executed on remote node OTHER_NODE shows where it is executed Different operational characteristics for RBO &amp; CBO</p>
<p>RBO &#8211; Drags everything across the link and joins locally<br />
CBO &#8211; Uses cost estimates to determine whether to execute remotely or locally</p>
<p>SQL&gt;  explain plan for<br />
select *<br />
from dept@loop_link;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
SELECT STATEMENT REMOTE  [CHOOSE] Cost=1<br />
  TABLE ACCESS FULL DEPT [SJD.WORLD] [ANALYZED]</p>
<p>In this case the whole query has been sent to the remote site. The other column shows nothing.</p>
<p>SQL&gt; explain plan for<br />
select a.dname,avg(b.sal),max(b.sal)<br />
from dept@loop_link a, emp b<br />
where a.deptno=b.deptno<br />
group by a.dname<br />
order by max(b.sal),avg(b.sal) desc;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT   [CHOOSE] Cost=20<br />
  SORT ORDER BY  [:Q137003] [PARALLEL_TO_SERIAL]<br />
    SORT GROUP BY  [:Q137002] [PARALLEL_TO_PARALLEL]<br />
      NESTED LOOPS   [:Q137001] [PARALLEL_TO_PARALLEL]<br />
        REMOTE   [:Q137000] [PARALLEL_FROM_SERIAL]<br />
        TABLE ACCESS FULL EMP [:Q137001] [ANALYZED]<br />
        [PARALLEL_COMBINED_WITH_PARENT]</p>
<p>Bind Variables</p>
<p>Bind variables are recommended in most cases because they promote sharing of sql code<br />
At parse time the parser has NO IDEA what the bind variable contains. With RBO this makes no difference but with CBO, which relies on accurate statistics to produce plans, this can be a problem.</p>
<p>Defining bind variables in sqlplus:</p>
<p>variable x varchar2(18);<br />
assigning values:<br />
begin<br />
 <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_mad.gif' alt=':x' class='wp-smiley' />  := &#8216;hello&#8217;;<br />
end;<br />
/</p>
<p>SQL&gt; explain plan for<br />
select *<br />
from dept<br />
where rowid = &#8216;:x&#8217;;</p>
<p>Query Plan<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
SELECT STATEMENT [CHOOSE] Cost=1<br />
  TABLE ACCESS BY ROWID DEPT [ANALYZED]</p>
<p>Parallel Query</p>
<p>Main indicators that a query is using PQO:</p>
<ul>
<li>[:Q1000004] entries in the explain plan</li>
<li>Checkout the other column for details of what the slaves are executing</li>
<li>v$pq_slave will show any parallel activity</li>
</ul>
<p>Columns to look in for information</p>
<ul>
<li>other &#8211; contains the query passed to the slaves</li>
<li>other_tag &#8211; describes the contents of other</li>
<li>object_node &#8211; indicates order of pqo slaves</li>
</ul>
<p>Parallel Query operates on a producer/consumer basis. When you specify parallel degree 4 oracle tries to allocate 4 producer slaves and 4 consumer slaves. The producers can feed any of the consumers. If there are only 2 slaves available then we use these. If there is only 1 slave available then we go serial If there are none available then we use serial. If parallel_min_percent is set then we error ora 12827 instead of using a lower number of slaves or going serial</p>
<p>Consumer processes typically perform a sorting function. If there is no requirement for the data to be sorted then the consumer slaves are not produced and we end up with the number of slaves used matching the degree of parallelism as opposed to being 2x the degree.</p>
<p>Parallel Terms</p>
<table border="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td width="50%" valign="top">PARALLEL_FROM_SERIAL</td>
<td width="50%" valign="top">This means that source of the data is serial but it is passed to a parallel consumer</td>
</tr>
<tr>
<td width="50%" valign="top">PARALLEL_TO_PARALLEL</td>
<td width="50%" valign="top">Both the consumer and the producer are  parallel</td>
</tr>
<tr>
<td width="50%" valign="top">PARALLEL_COMBINED_WITH_PARENT</td>
<td width="50%" valign="top">This operation has been combined with the parent operator. For example in a sort merge join the sort operations would be shown as PARALLEL_COMBINED_WITH_PARENT because the sort and the merge are handled as 1 operation.</td>
</tr>
<tr>
<td width="50%" valign="top">PARALELL_TO_SERIAL</td>
<td width="50%" valign="top">The source of the data is parallel but it is passed to a serial consumer. This typically will happen at the top of the explain plan but could occur anywhere</td>
</tr>
</tbody>
</table>
<p>Examples of parallel queries</p>
<p>Assumptions</p>
<p>OPTIMIZER_MODE = CHOOSE<br />
DEPT is small compared to EMP<br />
DEPT has an index (DEPT_INDX) on deptno column</p>
<p>Three examples are presented</p>
<p>Query #1:  Serial<br />
Query #2:  Parallel<br />
Query #3:  Parallel, with forced optimization to RULE and forced usage of DEPT_INDX</p>
<p>Sample Query #1 (Serial)</p>
<p>select A.dname, avg(B.sal), max(B.sal)<br />
from  dept A, emp B<br />
where A.deptno = B.deptno<br />
group by A.dname<br />
order by max(B.sal), avg(B.sal) desc;</p>
<p>Execution Plan #1 (Serial)</p>
<p>OBJECT_NAME                      OBJECT_NODE OTHER<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-  &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;-<br />
SELECT STATEMENT<br />
 SORT ORDER BY<br />
   SORT GROUP BY<br />
     MERGE JOIN<br />
       SORT JOIN<br />
         TABLE ACCESS FULL emp<br />
       SORT JOIN<br />
         TABLE ACCESS FULL dept</p>
<p>Notice that the object_node and other columns are empty</p>
<p>Sample Query #2 (Query #1 with parallel hints)</p>
<p>select <strong>/*+ parallel(B,4) parallel(A,4) */</strong><br />
A.dname, avg(B.sal), max(B.sal)<br />
from  dept A, emp B<br />
where A.deptno = B.deptno<br />
group by A.dname<br />
order by max(B.sal), avg(B.sal) desc;</p>
<p>Execution Plan #2  (Parallel)</p>
<p>OBJECT_NAME                      OBJECT_NODE OTHER<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-  &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;-<br />
SELECT STATEMENT      Cost = ??<br />
 SORT ORDER BY                   :Q55004     **[7]**<br />
   SORT GROUP BY                 :Q55003     **[6]**<br />
     MERGE JOIN                  :Q55002     **[5]**<br />
       SORT JOIN                 :Q55002     **[4]**<br />
         TABLE ACCESS FULL emp   :Q55001     **[2]**<br />
       SORT JOIN                 :Q55002     **[3]**<br />
         TABLE ACCESS FULL dept  :Q55000     **[1]**</p>
<p>Execution Plan #2  &#8212; OTHER column</p>
<p>**[1]**  (:Q55000) &#8220;PARALLEL_FROM_SERIAL&#8221;</p>
<p>Serial execution of SELECT DEPTNO, DNAME FROM DEPT</p>
<p>**[2]**  (:Q55001) &#8220;PARALLEL_TO_PARALLEL&#8221;</p>
<p>        SELECT /*+ ROWID(A1)*/<br />
        A1.&#8221;DEPTNO&#8221; C0, A1.&#8221;SAL&#8221; C1<br />
        FROM &#8220;EMP&#8221; A1<br />
        WHERE ROWID BETWEEN :1 AND :2</p>
<p>**[3]**  (:Q55002) &#8220;PARALLEL_COMBINED_WITH_PARENT&#8221;<br />
**[4]**  (:Q55002) &#8220;PARALLEL_COMBINED_WITH_PARENT&#8221;<br />
**[5]**  (:Q55002) &#8220;PARALLEL_TO_PARALLEL&#8221;</p>
<p>        SELECT /*+ ORDERED USE_MERGE(A2)*/<br />
        A2.C1 C0, A1.C1 C1<br />
        FROM :Q55001 A1,:Q55000 A2<br />
        WHERE A1.C0=A2.C0</p>
<p>**[6]**  (:Q55003) &#8220;PARALLEL_TO_PARALLEL&#8221;</p>
<p>        SELECT MAX(A1.C1) C0, AVG(A1.C1) C1, A1.C0 C2<br />
        FROM :Q55002 A1<br />
        GROUP BY A1.C0</p>
<p>**[7]**  (:Q55004) &#8220;PARALLEL_FROM_SERIAL&#8221;</p>
<p>        SELECT A1.C0 C0, A1.C1 C1, A1.C2 C2<br />
        FROM :Q55003 A1<br />
        ORDER BY A1.CO, A1.C1 DESC</p>
<p>Sample Query #3 (Query #2 with fudged hints)</p>
<p>select /*+ index(A dept_indx) <strong>parallel(B,4) parallel(A,4)</strong> */<br />
      A.dname, avg(B.sal), max(B.sal)<br />
from  dept A, emp B<br />
where A.deptno = B.deptno<br />
group by A.dname<br />
order by max(B.sal), avg(B.sal) desc;</p>
<p>Execution Plan #3  (Parallel)</p>
<p>OBJECT_NAME                         OBJECT_NODE OTHER<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;-<br />
SELECT STATEMENT          Cost = ??<br />
 SORT ORDER BY                      :Q58002     **[6]**<br />
   SORT GROUP BY                    :Q58001     **[5]**<br />
     NESTED LOOPS JOIN              :Q58000     **[4]**<br />
       TABLE ACCESS FULL emp        :Q58000     **[3]**<br />
       TABLE ACCESS BY ROWID dept   :Q58000     **[2]**<br />
         INDEX RANGE SCAN dept_indx :Q58000     **[1]**</p>
<p>Execution Plan #3  &#8212; OTHER column</p>
<p>**[1]**  (:Q58000) &#8220;PARALLEL_COMBINED_WITH_PARENT&#8221;<br />
**[2]**  (:Q58000) &#8220;PARALLEL_COMBINED_WITH_PARENT&#8221;<br />
**[3]**  (:Q58000) &#8220;PARALLEL_COMBINED_WITH_PARENT&#8221;<br />
**[4]**  (:Q58000) &#8220;PARALLEL_TO_PARALLEL&#8221;</p>
<p>        SELECT /*+ ORDERED USE_NL(A2) INDEX(A2) */<br />
        A2.&#8221;DNAME&#8221; C0, A1.C0 C1<br />
        FROM<br />
          (SELECT /*+ ROWID(A3) */<br />
           A3.&#8221;SAL&#8221; CO, A3.&#8221;DEPTNO&#8221; C1<br />
           FROM &#8220;EMP&#8221; A3<br />
           WHERE ROWID BETWEEN :1 AND :2) A1,<br />
          &#8220;DEPT&#8221; A2<br />
        WHERE A2.&#8221;DEPTNO&#8221; = A1.C1</p>
<p>**[5]**  (:Q58001) &#8220;PARALLEL_TO_PARALLEL&#8221;</p>
<p>        SELECT MAX(A1.C1) C0, AVG(A1.C1) C1, A1.C0 C2<br />
        FROM :Q58000 A1<br />
        GROUP BY A1.C0</p>
<p>**[6]**  (:Q58002) &#8220;PARALLEL_TO_SERIAL&#8221;</p>
<p>        SELECT A1.C0 C0, A1.C1 C1, A1.C2 C2<br />
        FROM :Q58001 A1<br />
        ORDER BY A1.C0, A1.C1 DESC</p>
<p>How to obtain explain plans</p>
<p>Explain plan for</p>
<p>Main advantage is that it does not actually run the query &#8211; just parses the sql. This means that it executes quickly. In the early stages of tuning explain plan gives you an idea of the potential performance of your query without actually running it. You can then make a judgement as to any modifications you may choose to make.</p>
<p>Autotrace</p>
<p>Autotrace can be configured to run the sql &amp; gives a plan  and statistics afterwards or just give you an explain plan without executing the query.</p>
<p>Tkprof</p>
<p>Analyzes trace file</td>
</tr>
</tbody>
</table>
<p>ting the query.</p>
<p>Tkprof</p>
<p> </p>
<p>This article is from ; <a href="http://www.akadia.com/services/ora_interpreting_explain_plan.html">http://www.akadia.com/services/ora_interpreting_explain_plan.html</a></p>
<p>Analyzes trace file</td>
</tr>
</tbody>
</table>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/enginozer.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/enginozer.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/enginozer.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/enginozer.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/enginozer.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/enginozer.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/enginozer.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/enginozer.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/enginozer.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/enginozer.wordpress.com/64/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=64&subd=enginozer&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://enginozer.wordpress.com/2009/09/25/oracle-explain-plan-2-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d115faa5b1011c2837cb2de5b694342f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">enginozer</media:title>
		</media:content>

		<media:content url="http://enginozer.wordpress.com/img/zurueck.gif" medium="image">
			<media:title type="html">Zurück</media:title>
		</media:content>

		<media:content url="http://enginozer.wordpress.com/img/bullet-gruen.gif" medium="image" />

		<media:content url="http://enginozer.wordpress.com/img/bullet-gruen.gif" medium="image" />

		<media:content url="http://enginozer.wordpress.com/img/zurueck.gif" medium="image">
			<media:title type="html">Zurück</media:title>
		</media:content>

		<media:content url="http://enginozer.wordpress.com/img/bullet-gruen.gif" medium="image" />

		<media:content url="http://enginozer.wordpress.com/img/bullet-gruen.gif" medium="image" />
	</item>
		<item>
		<title>Oracle Explain Plan</title>
		<link>http://enginozer.wordpress.com/2009/09/25/oracle-explain-plan-2/</link>
		<comments>http://enginozer.wordpress.com/2009/09/25/oracle-explain-plan-2/#comments</comments>
		<pubDate>Fri, 25 Sep 2009 07:17:09 +0000</pubDate>
		<dc:creator>Engin ÖZER</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://enginozer.wordpress.com/?p=62</guid>
		<description><![CDATA[ 
Oracle Explain Plan Terms:
 
Table Access Full: Oracle reads every row in selected table. In terms of that there is no primary key or index defined with the columns that you use at your where clause Oracle makes full table access.
OPERATION                      OPTIONS         OBJECT_NAME
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;
SELECT STATEMENT
TABLE ACCESS                   FULL            Students
Selecting With Primary Keys:  Primary key defines a [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=62&subd=enginozer&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p> </p>
<p><strong>Oracle Explain Plan Terms:</strong></p>
<p> </p>
<p><strong>Table Access Full:</strong> Oracle reads every row in selected table. In terms of that there is no primary key or index defined with the columns that you use at your where clause Oracle makes full table access.</p>
<p>OPERATION                      OPTIONS         OBJECT_NAME</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>SELECT STATEMENT</p>
<p>TABLE ACCESS                   FULL            Students</p>
<p><strong>Selecting With Primary Keys: </strong> Primary key defines a row uniquely. By using table’s primary key at where clause Oracle makes <strong>Index RowID Unique Scan</strong>   in order to select unique row which reduces our total cost so much.</p>
<pre>OPERATION                      OPTIONS         OBJECT_NAME
------------------------------ --------------- --------------------
SELECT STATEMENT
TABLE ACCESS                   BY INDEX ROWID  Students
INDEX                          UNIQUE SCAN     Students _PK</pre>
<p> </p>
<p><strong>Selecting With Ununique Indexes: </strong>Ununique indexes reduces the cost of full table scan. But, of course if we have change to use primary keys we should use them. If we can’t we can use other non-unique indexes. The reducement of cost varies due to index’s definition. If the uniqueness of our index columns raises retrieval time will go down. Because of this reason, use the criteria that will catch the fastest index for that query.</p>
<p>OPERATION                      OPTIONS         OBJECT_NAME</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>SELECT STATEMENT</p>
<p>TABLE ACCESS                   BY INDEX ROWID  Students</p>
<p>INDEX                          RANGE SCAN      Students_IDX1</p>
<p> </p>
<p><strong>Efficiency of Join Statements:  </strong>We should be very careful at writing join statements. The column you choose the join plays very important role here. The most important thing we have to consider at creating joins is using indexed columns at where clause. Let’s assume that there is a table “StudentMarks” keeping marks of students for some particular lesson.For example phisics. The statement following retrievs  all the marks of the students having the name “ENGİN”. StudentMarks table does not have any foreign key at student column. İts only index column is mark.</p>
<p>select s.name,s.surname,m.mark<br />
  from StudentMarks m, Students s<br />
 where s.name = ‘ENGİN’</p>
<p>   and s.id = m.studentid</p>
<p>   and m.mark between 10000 and 30000</p>
<p> </p>
<p>OPERATION                      OPTIONS         OBJECT_NAME</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>SELECT STATEMENT</p>
<p>NESTED LOOPS</p>
<p>TABLE ACCESS                   BY INDEX ROWID  Students</p>
<p>INDEX                          RANGE SCAN      Student_IDX2</p>
<p>TABLE ACCESS                   BY INDEX ROWID  StudentMarks</p>
<p>INDEX                          RANGE SCAN      StudentMarks_IDX3</p>
<p> </p>
<p>All the columns are catched by <strong>range scan</strong>.</p>
<p> </p>
<p><strong>Choosing The Fastest Index: </strong>Indexes varies by the mean of cost. To query with minimum cost, we have to keep in mind the table’s count of rows. We should always give our priority to most sized table by the mean of choosing where clauses. Let’s take an example to examine this furter;<strong> </strong></p>
<p><strong> </strong></p>
<p>select s.name,s.surname,m.mark<br />
  from StudentMarks m, Students s<br />
 where s.name = ‘ENGİN’</p>
<p>   and s.id = m.studentid</p>
<p>   and m.mark between 10000 and 30000</p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p>Will produce this plan:</p>
<p>OPERATION                      OPTIONS         OBJECT_NAME</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>SELECT STATEMENT</p>
<p>NESTED LOOPS</p>
<p>TABLE ACCESS                   BY INDEX ROWID  Students</p>
<p>INDEX                          RANGE SCAN      Students_IDX2</p>
<p>TABLE ACCESS                   BY INDEX ROWID  StudentMarks</p>
<p>INDEX                          RANGE SCAN      StudentMarks _IDX3</p>
<p>Oracle, tries to determine whether students or studentsmarks table is the best to index first. At the term oracle can not decide, Oracle starts indexing at the order of right to left at from clause. Be careful about this query. It is the same with the one above. But, at this query Oracle starts indexing with StudentMarks table.</p>
<p> select s.name,s.surname,m.mark<br />
  from Students s, StudentMarks m<br />
 where s.name = ‘ENGİN’</p>
<p>   and s.id = m.studentid</p>
<p>   and m.mark between 10000 and 30000</p>
<p> </p>
<p>This query produces this plan:</p>
<p>OPERATION                      OPTIONS         OBJECT_NAME</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;</p>
<p>SELECT STATEMENT</p>
<p>NESTED LOOPS</p>
<p>TABLE ACCESS                   BY INDEX ROWID  StudentMarks</p>
<p>INDEX                          RANGE SCAN      StudentMarks _IDX3</p>
<p>TABLE ACCESS                   BY INDEX ROWID  Students</p>
<p>INDEX                          RANGE SCAN      Students_IDX2</p>
<p> </p>
<p>StudentMarks.mark is queried first because we told Oracle to do so.</p>
<p> </p>
<p> </p>
<p><strong> </strong></p>
<p><strong>Utilizing Multiple Column Indexes</strong></p>
<p><strong>Utilizing Multiple Column Indexes: </strong>Multiple Column indexes uses more than one column for indexing. In order to use that index we have to search for the first column before we search second column in the index. To get more efficient queries from that indexes we have to choose index criteria more uniquely. Unique columns are also indexes. It is the best way to use unique indexes to get one specific row.</p>
<p><strong>Oracle Explan Plan Terms</strong></p>
<p>Whenever you read or write data in Oracle, you do so by issuing an <a href="http://www.adp-gmbh.ch/ora/concepts/sql_stmt.html">SQL statement</a>. One of Oracle&#8217;s task when it receives such a statement is to build a <a href="http://www.adp-gmbh.ch/ora/sql/execution_plan.html">query execution plan</a>. An execution plan defines how Oracle finds or writes the data. For example, an important decision that Oracle has to take is if it uses indexes or not. And if there are more indexes, which of these is used. All this is contained in an execution plan.</p>
<p>If one wants to explore such an execution plan, Oracle provides the SQL statement <strong>EXPLAIN PLAN</strong> to determine this.</p>
<p>The general syntax of EXPLAIN PLAN is:</p>
<pre><a href="http://www.adp-gmbh.ch/ora/sql/explain_plan.html">explain plan</a> for your-precious-sql-statement;</pre>
<p> </p>
<p>If you do an EXPLAIN PLAN, Oracle will analyze the statment and fill a special table with the Execution plan for that statement. You can indicate which table has to be filled with the following SQL command:</p>
<pre><a href="http://www.adp-gmbh.ch/ora/sql/explain_plan.html">explain plan</a> into table_name for your-precious-sql-statement;</pre>
<p>If you omit the INTO TABLE_NAME clause, Oracle fills a table named PLAN_TABLE by default.</p>
<p> </p>
<p>Whenever you read or write data in Oracle, you do so by issuing an <a href="http://www.adp-gmbh.ch/ora/concepts/sql_stmt.html">SQL statement</a>. One of Oracle&#8217;s task when it receives such a statement is to build a <a href="http://www.adp-gmbh.ch/ora/sql/execution_plan.html">query execution plan</a>. An execution plan defines how Oracle finds or writes the data. For example, an important decision that Oracle has to take is if it uses indexes or not. And if there are more indexes, which of these is used. All this is contained in an execution plan.</p>
<p>If one wants to explore such an execution plan, Oracle provides the SQL statement <strong>EXPLAIN PLAN</strong> to determine this.</p>
<p>The general syntax of EXPLAIN PLAN is:</p>
<pre><a href="http://www.adp-gmbh.ch/ora/sql/explain_plan.html">explain plan</a> for your-precious-sql-statement;</pre>
<p>If you do an EXPLAIN PLAN, Oracle will analyze the statment and fill a special table with the Execution plan for that statement. You can indicate which table has to be filled with the following SQL command:</p>
<pre><a href="http://www.adp-gmbh.ch/ora/sql/explain_plan.html">explain plan</a> into table_name for your-precious-sql-statement;</pre>
<p>If you omit the INTO TABLE_NAME clause, Oracle fills a table named PLAN_TABLE by default.</p>
<h2>The Plan Table</h2>
<p>The plan table is the table that Oracle fills when you have it explain an execution plan for an SQL statement. You must make sure such a plan table exists. Oracle ships with the script UTLXPLAN.SQL which creates this table, named PLAN_TABLE (which is the default name used by EXPLAIN PLAN). If you like, however, you can choose any other name for the plan table, as long as you have been granted insert on it and it has all the fields as <a href="http://www.adp-gmbh.ch/ora/exp_plan/plan_table.html">here</a>.</p>
<h3>The fields (attributes) within the plan table</h3>
<p>Arguably, the <strong>most important fields</strong> within the plan table are <em>operation</em>, <em>option</em>, <em>object_name</em>, <em>id</em>, and <em>parent_id</em>. The pair operation and object_name define what operation would be done on (or with) object_name. If an operation has an id which other operations have as parent_id, it means the other operations feed their result to the parent.</p>
<p> </p>
<p>Possible <strong>values for operation</strong> are:</p>
<ul>
<li>DELETE STATEMENT</li>
<li>INSERT STATEMENT</li>
<li>SELECT STATEMENT</li>
<li>UPDATE STATEMENT</li>
<li>AND-EQUAL</li>
<li>CONNECT BY</li>
<li>CONCATENATION</li>
<li>COUNT</li>
<li>DOMAIN INDEX</li>
<li>FILTER</li>
<li>FIRST ROW</li>
<li>FOR UPDATE</li>
<li>HASH JOIN</li>
<li>INDEX</li>
<li>INLIST ITERATOR</li>
<li>INTERSECTION</li>
<li><a href="http://www.adp-gmbh.ch/ora/sql/join/join_methods.html#merge_join">MERGE JOIN</a></li>
<li>MINUS</li>
<li><a href="http://www.adp-gmbh.ch/ora/sql/join/join_methods.html#nested_loops">NESTED LOOPS</a></li>
<li>PARTITION,</li>
<li>REMOTE</li>
<li>SEQUENCE</li>
<li>SORT</li>
<li>TABLE ACCESS</li>
<li>UNION</li>
<li>VIEW</li>
</ul>
<p> </p>
<p> </p>
<p><strong>Option</strong> tells more about how an operation would be done. For example, the operation TABLE ACCESS can have the options: FULL or BY ROWID or many others. Full in this case means, that the entire table is accessed (takes a long time if table is huge) whereas BY ROWID means, Oracle knows where (from which block) the rows are to be retrieved, which makes the time to access the table shorter.</p>
<h3>dbms_xplan</h3>
<p>As of 9i, <a href="http://www.adp-gmbh.ch/ora/plsql/dbms_xplan.html">dbms_xplan</a> can be used to format the plan table.</p>
<h2>Operations</h2>
<p>The following table is used to demonstrate EXPLAIN PLAN:</p>
<p>create table test_for_ep (a number, b varchar2(100));</p>
<p>Now, let&#8217;s explain the plan for selecting everything on that table:</p>
<p>delete plan_table;</p>
<p>explain plan for select /*+ rule */ * from test_for_ep where a = 5;</p>
<p> </p>
<h2>Displaying the execution plan</h2>
<p>In order to view the explained plan, we have to query the plan table:</p>
<pre>select
  substr (lpad(' ', level-1) || operation || ' (' || options || ')',1,30 ) "Operation",
  object_name                                                              "Object"
from
  plan_table
<a href="http://www.adp-gmbh.ch/ora/sql/connect_by.html#start_with">start with</a> id = 0
<a href="http://www.adp-gmbh.ch/ora/sql/connect_by.html#connect_by_prior">connect by prior</a>;</pre>
<p>This statement is a simplified version of <strong>utlxpls.sql</strong>. utlxpls.sql is a script that Oracle ships.</p>
<p>Here&#8217;s the output of the explain plan:</p>
<pre>SELECT STATEMENT ()
 TABLE ACCESS (FULL)           TEST_FOR_EP</pre>
<p>First, take a look at the indention: TABLE ACCESS is indented right. In an explain plan output, the more indented an operation is, the earlier it is executed. And the result of this operation (or operations, if more than one have are equally indented AND have the same parent) is then feeded to the parent operation. In this case, TABLE ACCESS is made first, and its result feeded to SELECT STATEMENT (which is not an actual operation). Note the FULL in paranthesis in TABLE ACCESS: this means that the entire table is accessed.</p>
<p>Btw, <a href="http://www.adp-gmbh.ch/ora/sqlplus/index.html">sql*plus</a> automatically explains the plan for you if <a href="http://www.adp-gmbh.ch/ora/sqlplus/autotrace.html">autotrace</a> is enabled.</p>
<p>Now, let&#8217;s create an index on that table:</p>
<pre>create index test_for_ep_ix on test_for_ep (a);</pre>
<p>And do the same select statement again:</p>
<pre>delete plan_table;
explain plan for select /*+ rule */ * from test_for_ep where a = 5;</pre>
<p>The plan is now:</p>
<pre>SELECT STATEMENT ()
 TABLE ACCESS (BY INDEX <strong>ROWID</strong>) TEST_FOR_EP
  INDEX (RANGE SCAN)           TEST_FOR_EP_IX</pre>
<p>Obviously, the index (TEST_FOR_EP_IX) is used first (most indented) then used for a TABLE ACCESS, second most indented, then the result is returned. The table access is not done by a <a href="http://www.adp-gmbh.ch/ora/tuning/fulltablescan.html">full table scan</a> but rather by using the data&#8217;s rowid.</p>
<h3>INDEX</h3>
<p>In the last example, Oracle employed an INDEX (RANGE SCAN). The RANGE SCAN basically means, that the index was used, but that it can return more than one row. Now, we create a unique index to see how this alters the explain plan:</p>
<pre>create table test_for_ep (a number, b varchar2(100), constraint uq_tp unique(a));
 
delete plan_table;
explain plan for select /*+ rule */ * from test_for_ep where a = 5;</pre>
<p>The explained plan is:</p>
<pre>SELECT STATEMENT ()
 TABLE ACCESS (BY INDEX ROWID) TEST_FOR_EP
  INDEX (<strong>UNIQUE SCAN</strong>)          UQ_TP</pre>
<p>INDEX (UNIQUE SCAN) means, that this index is used, and it sort of guarantees that this index returnes exactly one <a href="http://www.adp-gmbh.ch/ora/concepts/rowid.html">rowid</a>. What happens, if we query the field not for equality but for greater than (a&gt;5)?</p>
<pre>explain plan for select /*+ rule */ * from test_for_ep where a &gt; 5;</pre>
<p>Here, we see that the index is used, but for a RANGE SCAN:</p>
<pre>SELECT STATEMENT ()
 TABLE ACCESS (BY INDEX ROWID) TEST_FOR_EP
  INDEX (<strong>RANGE SCAN</strong>)           UQ_TP</pre>
<p>If we only query fields of a table that are already in an index, Oracle doesn&#8217;t have to read the data blocks because it can get the relevant data from the index:</p>
<pre>create table test_for_ep (a number, b varchar2(100), constraint uq_tp unique(a));
 
delete plan_table;
explain plan for select /*+ rule */ a from test_for_ep where a &gt; 5 and a &lt; 50;</pre>
<p>Here&#8217;s the <a href="http://www.adp-gmbh.ch/ora/sql/execution_plan.html">query execution plan</a>execution plan. No table access anymore!</p>
<pre>SELECT STATEMENT ()
 INDEX (RANGE SCAN)            UQ_TP</pre>
<h3>MERGE JOIN</h3>
<p>See <a href="http://www.adp-gmbh.ch/ora/sql/join/join_methods.html#merge_join">here</a>. The first table&#8217;s join key is <strong>ba</strong> while the second table&#8217;s join key is <strong>aa</strong>.</p>
<pre>create table <strong>test_for_ep_a</strong> (aa number, ab varchar2(100));
create table <strong>test_for_ep_b</strong> (ba number, bb varchar2(100));</pre>
<p>Note, there are no indexes on both of the tables. Now, we join the tables on <strong>aa</strong> and <strong>ba</strong>:</p>
<pre>explain plan for
  select /*+ rule */ a.aa from test_for_ep_a a, test_for_ep_b b where
  a.aa=b.ba and a.aa &gt; 5;</pre>
<p>As there are no indexes, both tables must be TABLE ACCESSed (FULL). After these accesses, their results are sorted.</p>
<pre>SELECT STATEMENT ()
 MERGE JOIN ()
  SORT (JOIN)
   TABLE ACCESS (FULL)         TEST_FOR_EP_B
  SORT (JOIN)
   TABLE ACCESS (FULL)         TEST_FOR_EP_A</pre>
<p>Note MERGE JOINs can only be used for equi joins, as is demonstrated in NESTED LOOPS</p>
<p> </p>
<h3>NESTED LOOPS</h3>
<p>For each relevant row in the first table (driving table), find all matching rows in the other table (probed table).</p>
<p>See also <a href="http://www.adp-gmbh.ch/ora/sql/join/join_methods.html#nested_loops">here</a>.</p>
<pre>create table <strong>test_for_ep_a</strong> (aa number, ab varchar2(100));
create table <strong>test_for_ep_b</strong> (ba number, bb varchar2(100));
explain plan for
  select /*+ rule */ a.aa from test_for_ep_a a, test_for_ep_b b where
  a.aa &gt; b.ba and a.aa &gt; 5;</pre>
<p>Note, there is no equi join to join test_for_ep_a and test_for_ep_b, (a.aa &gt; b.ba)</p>
<pre>SELECT STATEMENT ()
 NESTED LOOPS ()
  TABLE ACCESS (FULL)          TEST_FOR_EP_B
  TABLE ACCESS (FULL)          TEST_FOR_EP_A</pre>
<p>Now, we put an index on TEST_FOR_EP_B and see how that influences our nested loop:</p>
<pre>create table test_for_ep_a (aa number, ab varchar2(100));
create table test_for_ep_b (ba number, bb varchar2(100), <strong>constraint uq_ba unique(ba)</strong>);
 
delete plan_table;
explain plan for
  select /*+ rule */ a.aa from test_for_ep_a a, test_for_ep_b b where
  a.aa &gt; b.ba;</pre>
<p>The plan is:</p>
<pre>SELECT STATEMENT ()
 NESTED LOOPS ()
  TABLE ACCESS (FULL)          TEST_FOR_EP_A
  INDEX (RANGE SCAN)           <strong>UQ_BA</strong></pre>
<p>Interpreted, this means: TEST_FOR_EP_A is fully accessed and for each row, TEST_FOR_EP_B (or more accurately, its index UQ_BA) is probed. Thinking about it, this makes sense, doing the costly TABLE ACCESS once and use the index for each row. Then again, thinking about it, if TEST_FOR_EP_A is very small nad TEST_FOR_EP_B is large, this doesn&#8217;t make sense anymore. This is when the Cost Based Optimizer comes into play.</p>
<h2>Sorts</h2>
<h3>Aggregate Sorts</h3>
<p>Whenever a result set must be sorted, the operation is <strong>sort</strong>. If this sort is used to return a single row (for example <strong>max</strong> or <strong>min</strong>) the options is <strong>AGGREGATE</strong>. Consider the following example:</p>
<pre>create table t_ep (
  w date,
  v number,
  x varchar2(40)
);
 
 
delete plan_table;
explain plan for select /*+ rule */ max(w) from t_ep where v=4;
SELECT STATEMENT ()
 <strong>SORT (AGGREGATE)</strong>
  TABLE ACCESS (FULL)          T_EP</pre>
<p>Now: creating an index:</p>
<pre>alter table t_ep add constraint uq_t_ep unique(v);
delete plan_table;
explain plan for select /*+ rule */ max(w) from t_ep where v=4;
SELECT STATEMENT ()
 SORT (AGGREGATE)
  TABLE ACCESS (BY INDEX ROWID) T_EP
   INDEX (UNIQUE SCAN)          UQ_T_EP</pre>
<h2>TKPROF</h2>
<p>If you want to know, how much time an SQL statement acutally used, use <a href="http://www.adp-gmbh.ch/ora/tuning/tkprof/index.html">TKPROF</a></p>
<p> </p>
<p><strong> </strong></p>
<p><strong>References</strong>Top of Form</p>
<p><strong> </strong></p>
<p>-          <a href="http://www.evolt.org/node/2986"><strong>http://www.evolt.org/node/2986</strong></a><strong> </strong></p>
<p><strong>Adam Patrick, </strong>Use Oracle&#8217;s Explain Plan to Tune Your Queries, <strong>August 24, 2000</strong></p>
<p>-          <a href="http://www.adp-gmbh.ch/ora/explainplan.html"><strong>http://www.adp-gmbh.ch/ora/explainplan.html</strong></a><strong></strong></p>
<p><strong> </strong></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/enginozer.wordpress.com/62/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/enginozer.wordpress.com/62/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/enginozer.wordpress.com/62/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/enginozer.wordpress.com/62/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/enginozer.wordpress.com/62/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/enginozer.wordpress.com/62/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/enginozer.wordpress.com/62/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/enginozer.wordpress.com/62/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/enginozer.wordpress.com/62/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/enginozer.wordpress.com/62/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=62&subd=enginozer&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://enginozer.wordpress.com/2009/09/25/oracle-explain-plan-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d115faa5b1011c2837cb2de5b694342f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">enginozer</media:title>
		</media:content>
	</item>
		<item>
		<title>Oracle Explain Plan</title>
		<link>http://enginozer.wordpress.com/2009/09/25/oracle-explain-plan/</link>
		<comments>http://enginozer.wordpress.com/2009/09/25/oracle-explain-plan/#comments</comments>
		<pubDate>Fri, 25 Sep 2009 07:13:50 +0000</pubDate>
		<dc:creator>Engin ÖZER</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://enginozer.wordpress.com/?p=58</guid>
		<description><![CDATA[Oracle Explain Plan Terms:
Table Access Full: Oracle reads every row in selected table. In terms of that there is no primary key or index defined with the columns that you use at your where clause Oracle makes full table access.
OPERATION                [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=58&subd=enginozer&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Oracle Explain Plan Terms:</p>
<p>Table Access Full: Oracle reads every row in selected table. In terms of that there is no primary key or index defined with the columns that you use at your where clause Oracle makes full table access.<br />
OPERATION                      OPTIONS         OBJECT_NAME<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT<br />
TABLE ACCESS                   FULL            Students<br />
Selecting With Primary Keys:  Primary key defines a row uniquely. By using table’s primary key at where clause Oracle makes Index RowID Unique Scan   in order to select unique row which reduces our total cost so much.<br />
OPERATION                      OPTIONS         OBJECT_NAME<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT<br />
TABLE ACCESS                   BY INDEX ROWID  Students<br />
INDEX                          UNIQUE SCAN     Students _PK</p>
<p>Selecting With Ununique Indexes: Ununique indexes reduces the cost of full table scan. But, of course if we have change to use primary keys we should use them. If we can’t we can use other non-unique indexes. The reducement of cost varies due to index’s definition. If the uniqueness of our index columns raises retrieval time will go down. Because of this reason, use the criteria that will catch the fastest index for that query.<br />
OPERATION                      OPTIONS         OBJECT_NAME<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT<br />
TABLE ACCESS                   BY INDEX ROWID  Students<br />
INDEX                          RANGE SCAN      Students_IDX1</p>
<p>Efficiency of Join Statements:  We should be very careful at writing join statements. The column you choose the join plays very important role here. The most important thing we have to consider at creating joins is using indexed columns at where clause. Let’s assume that there is a table “StudentMarks” keeping marks of students for some particular lesson.For example phisics. The statement following retrievs  all the marks of the students having the name “ENGİN”. StudentMarks table does not have any foreign key at student column. İts only index column is mark.<br />
select s.name,s.surname,m.mark<br />
  from StudentMarks m, Students s<br />
 where s.name = ‘ENGİN’<br />
   and s.id = m.studentid<br />
   and m.mark between 10000 and 30000 </p>
<p>OPERATION                      OPTIONS         OBJECT_NAME<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT<br />
NESTED LOOPS<br />
TABLE ACCESS                   BY INDEX ROWID  Students<br />
INDEX                          RANGE SCAN      Student_IDX2<br />
TABLE ACCESS                   BY INDEX ROWID  StudentMarks<br />
INDEX                          RANGE SCAN      StudentMarks_IDX3</p>
<p>All the columns are catched by range scan.</p>
<p>Choosing The Fastest Index: Indexes varies by the mean of cost. To query with minimum cost, we have to keep in mind the table’s count of rows. We should always give our priority to most sized table by the mean of choosing where clauses. Let’s take an example to examine this furter;</p>
<p>select s.name,s.surname,m.mark<br />
  from StudentMarks m, Students s<br />
 where s.name = ‘ENGİN’<br />
   and s.id = m.studentid<br />
   and m.mark between 10000 and 30000 </p>
<p>Will produce this plan:<br />
OPERATION                      OPTIONS         OBJECT_NAME<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT<br />
NESTED LOOPS<br />
TABLE ACCESS                   BY INDEX ROWID  Students<br />
INDEX                          RANGE SCAN      Students_IDX2<br />
TABLE ACCESS                   BY INDEX ROWID  StudentMarks<br />
INDEX                          RANGE SCAN      StudentMarks _IDX3<br />
Oracle, tries to determine whether students or studentsmarks table is the best to index first. At the term oracle can not decide, Oracle starts indexing at the order of right to left at from clause. Be careful about this query. It is the same with the one above. But, at this query Oracle starts indexing with StudentMarks table.<br />
 select s.name,s.surname,m.mark<br />
  from Students s, StudentMarks m<br />
 where s.name = ‘ENGİN’<br />
   and s.id = m.studentid<br />
   and m.mark between 10000 and 30000 </p>
<p>This query produces this plan:<br />
OPERATION                      OPTIONS         OBJECT_NAME<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
SELECT STATEMENT<br />
NESTED LOOPS<br />
TABLE ACCESS                   BY INDEX ROWID  StudentMarks<br />
INDEX                          RANGE SCAN      StudentMarks _IDX3<br />
TABLE ACCESS                   BY INDEX ROWID  Students<br />
INDEX                          RANGE SCAN      Students_IDX2</p>
<p>StudentMarks.mark is queried first because we told Oracle to do so.</p>
<p>Utilizing Multiple Column Indexes<br />
Utilizing Multiple Column Indexes: Multiple Column indexes uses more than one column for indexing. In order to use that index we have to search for the first column before we search second column in the index. To get more efficient queries from that indexes we have to choose index criteria more uniquely. Unique columns are also indexes. It is the best way to use unique indexes to get one specific row.<br />
Oracle Explan Plan Terms<br />
Whenever you read or write data in Oracle, you do so by issuing an SQL statement. One of Oracle&#8217;s task when it receives such a statement is to build a query execution plan. An execution plan defines how Oracle finds or writes the data. For example, an important decision that Oracle has to take is if it uses indexes or not. And if there are more indexes, which of these is used. All this is contained in an execution plan.<br />
If one wants to explore such an execution plan, Oracle provides the SQL statement EXPLAIN PLAN to determine this.<br />
The general syntax of EXPLAIN PLAN is:<br />
explain plan for your-precious-sql-statement;</p>
<p>If you do an EXPLAIN PLAN, Oracle will analyze the statment and fill a special table with the Execution plan for that statement. You can indicate which table has to be filled with the following SQL command:<br />
explain plan into table_name for your-precious-sql-statement;<br />
If you omit the INTO TABLE_NAME clause, Oracle fills a table named PLAN_TABLE by default. </p>
<p>Whenever you read or write data in Oracle, you do so by issuing an SQL statement. One of Oracle&#8217;s task when it receives such a statement is to build a query execution plan. An execution plan defines how Oracle finds or writes the data. For example, an important decision that Oracle has to take is if it uses indexes or not. And if there are more indexes, which of these is used. All this is contained in an execution plan.<br />
If one wants to explore such an execution plan, Oracle provides the SQL statement EXPLAIN PLAN to determine this.<br />
The general syntax of EXPLAIN PLAN is:<br />
explain plan for your-precious-sql-statement;<br />
If you do an EXPLAIN PLAN, Oracle will analyze the statment and fill a special table with the Execution plan for that statement. You can indicate which table has to be filled with the following SQL command:<br />
explain plan into table_name for your-precious-sql-statement;<br />
If you omit the INTO TABLE_NAME clause, Oracle fills a table named PLAN_TABLE by default.<br />
The Plan Table<br />
The plan table is the table that Oracle fills when you have it explain an execution plan for an SQL statement. You must make sure such a plan table exists. Oracle ships with the script UTLXPLAN.SQL which creates this table, named PLAN_TABLE (which is the default name used by EXPLAIN PLAN). If you like, however, you can choose any other name for the plan table, as long as you have been granted insert on it and it has all the fields as here.<br />
The fields (attributes) within the plan table<br />
Arguably, the most important fields within the plan table are operation, option, object_name, id, and parent_id. The pair operation and object_name define what operation would be done on (or with) object_name. If an operation has an id which other operations have as parent_id, it means the other operations feed their result to the parent. </p>
<p>Possible values for operation are:<br />
•	DELETE STATEMENT<br />
•	INSERT STATEMENT<br />
•	SELECT STATEMENT<br />
•	UPDATE STATEMENT<br />
•	AND-EQUAL<br />
•	CONNECT BY<br />
•	CONCATENATION<br />
•	COUNT<br />
•	DOMAIN INDEX<br />
•	FILTER<br />
•	FIRST ROW<br />
•	FOR UPDATE<br />
•	HASH JOIN<br />
•	INDEX<br />
•	INLIST ITERATOR<br />
•	INTERSECTION<br />
•	MERGE JOIN<br />
•	MINUS<br />
•	NESTED LOOPS<br />
•	PARTITION,<br />
•	REMOTE<br />
•	SEQUENCE<br />
•	SORT<br />
•	TABLE ACCESS<br />
•	UNION<br />
•	VIEW </p>
<p>Option tells more about how an operation would be done. For example, the operation TABLE ACCESS can have the options: FULL or BY ROWID or many others. Full in this case means, that the entire table is accessed (takes a long time if table is huge) whereas BY ROWID means, Oracle knows where (from which block) the rows are to be retrieved, which makes the time to access the table shorter.<br />
dbms_xplan<br />
As of 9i, dbms_xplan can be used to format the plan table.<br />
Operations<br />
The following table is used to demonstrate EXPLAIN PLAN:<br />
create table test_for_ep (a number, b varchar2(100));<br />
Now, let&#8217;s explain the plan for selecting everything on that table:<br />
delete plan_table;<br />
explain plan for select /*+ rule */ * from test_for_ep where a = 5;</p>
<p>Displaying the execution plan<br />
In order to view the explained plan, we have to query the plan table:<br />
select<br />
  substr (lpad(&#8216; &#8216;, level-1) || operation || &#8216; (&#8216; || options || &#8216;)&#8217;,1,30 ) &#8220;Operation&#8221;,<br />
  object_name                                                              &#8220;Object&#8221;<br />
from<br />
  plan_table<br />
start with id = 0<br />
connect by prior id=parent_id;<br />
This statement is a simplified version of utlxpls.sql. utlxpls.sql is a script that Oracle ships.<br />
Here&#8217;s the output of the explain plan:<br />
SELECT STATEMENT ()<br />
 TABLE ACCESS (FULL)           TEST_FOR_EP<br />
First, take a look at the indention: TABLE ACCESS is indented right. In an explain plan output, the more indented an operation is, the earlier it is executed. And the result of this operation (or operations, if more than one have are equally indented AND have the same parent) is then feeded to the parent operation. In this case, TABLE ACCESS is made first, and its result feeded to SELECT STATEMENT (which is not an actual operation). Note the FULL in paranthesis in TABLE ACCESS: this means that the entire table is accessed.<br />
Btw, sql*plus automatically explains the plan for you if autotrace is enabled.<br />
Now, let&#8217;s create an index on that table:<br />
create index test_for_ep_ix on test_for_ep (a);<br />
And do the same select statement again:<br />
delete plan_table;<br />
explain plan for select /*+ rule */ * from test_for_ep where a = 5;<br />
The plan is now:<br />
SELECT STATEMENT ()<br />
 TABLE ACCESS (BY INDEX ROWID) TEST_FOR_EP<br />
  INDEX (RANGE SCAN)           TEST_FOR_EP_IX<br />
Obviously, the index (TEST_FOR_EP_IX) is used first (most indented) then used for a TABLE ACCESS, second most indented, then the result is returned. The table access is not done by a full table scan but rather by using the data&#8217;s rowid.<br />
INDEX<br />
In the last example, Oracle employed an INDEX (RANGE SCAN). The RANGE SCAN basically means, that the index was used, but that it can return more than one row. Now, we create a unique index to see how this alters the explain plan:<br />
create table test_for_ep (a number, b varchar2(100), constraint uq_tp unique(a));</p>
<p>delete plan_table;<br />
explain plan for select /*+ rule */ * from test_for_ep where a = 5;<br />
The explained plan is:<br />
SELECT STATEMENT ()<br />
 TABLE ACCESS (BY INDEX ROWID) TEST_FOR_EP<br />
  INDEX (UNIQUE SCAN)          UQ_TP<br />
INDEX (UNIQUE SCAN) means, that this index is used, and it sort of guarantees that this index returnes exactly one rowid. What happens, if we query the field not for equality but for greater than (a&gt;5)?<br />
explain plan for select /*+ rule */ * from test_for_ep where a &gt; 5;<br />
Here, we see that the index is used, but for a RANGE SCAN:<br />
SELECT STATEMENT ()<br />
 TABLE ACCESS (BY INDEX ROWID) TEST_FOR_EP<br />
  INDEX (RANGE SCAN)           UQ_TP<br />
If we only query fields of a table that are already in an index, Oracle doesn&#8217;t have to read the data blocks because it can get the relevant data from the index:<br />
create table test_for_ep (a number, b varchar2(100), constraint uq_tp unique(a));</p>
<p>delete plan_table;<br />
explain plan for select /*+ rule */ a from test_for_ep where a &gt; 5 and a  5;<br />
As there are no indexes, both tables must be TABLE ACCESSed (FULL). After these accesses, their results are sorted.<br />
SELECT STATEMENT ()<br />
 MERGE JOIN ()<br />
  SORT (JOIN)<br />
   TABLE ACCESS (FULL)         TEST_FOR_EP_B<br />
  SORT (JOIN)<br />
   TABLE ACCESS (FULL)         TEST_FOR_EP_A<br />
Note MERGE JOINs can only be used for equi joins, as is demonstrated in NESTED LOOPS </p>
<p>NESTED LOOPS<br />
For each relevant row in the first table (driving table), find all matching rows in the other table (probed table).<br />
See also here.<br />
create table test_for_ep_a (aa number, ab varchar2(100));<br />
create table test_for_ep_b (ba number, bb varchar2(100));<br />
explain plan for<br />
  select /*+ rule */ a.aa from test_for_ep_a a, test_for_ep_b b where<br />
  a.aa &gt; b.ba and a.aa &gt; 5;<br />
Note, there is no equi join to join test_for_ep_a and test_for_ep_b, (a.aa &gt; b.ba)<br />
SELECT STATEMENT ()<br />
 NESTED LOOPS ()<br />
  TABLE ACCESS (FULL)          TEST_FOR_EP_B<br />
  TABLE ACCESS (FULL)          TEST_FOR_EP_A<br />
Now, we put an index on TEST_FOR_EP_B and see how that influences our nested loop:<br />
create table test_for_ep_a (aa number, ab varchar2(100));<br />
create table test_for_ep_b (ba number, bb varchar2(100), constraint uq_ba unique(ba));</p>
<p>delete plan_table;<br />
explain plan for<br />
  select /*+ rule */ a.aa from test_for_ep_a a, test_for_ep_b b where<br />
  a.aa &gt; b.ba;<br />
The plan is:<br />
SELECT STATEMENT ()<br />
 NESTED LOOPS ()<br />
  TABLE ACCESS (FULL)          TEST_FOR_EP_A<br />
  INDEX (RANGE SCAN)           UQ_BA<br />
Interpreted, this means: TEST_FOR_EP_A is fully accessed and for each row, TEST_FOR_EP_B (or more accurately, its index UQ_BA) is probed. Thinking about it, this makes sense, doing the costly TABLE ACCESS once and use the index for each row. Then again, thinking about it, if TEST_FOR_EP_A is very small nad TEST_FOR_EP_B is large, this doesn&#8217;t make sense anymore. This is when the Cost Based Optimizer comes into play.<br />
Sorts<br />
Aggregate Sorts<br />
Whenever a result set must be sorted, the operation is sort. If this sort is used to return a single row (for example max or min) the options is AGGREGATE. Consider the following example:<br />
create table t_ep (<br />
  w date,<br />
  v number,<br />
  x varchar2(40)<br />
);</p>
<p>delete plan_table;<br />
explain plan for select /*+ rule */ max(w) from t_ep where v=4;<br />
SELECT STATEMENT ()<br />
 SORT (AGGREGATE)<br />
  TABLE ACCESS (FULL)          T_EP<br />
Now: creating an index:<br />
alter table t_ep add constraint uq_t_ep unique(v);<br />
delete plan_table;<br />
explain plan for select /*+ rule */ max(w) from t_ep where v=4;<br />
SELECT STATEMENT ()<br />
 SORT (AGGREGATE)<br />
  TABLE ACCESS (BY INDEX ROWID) T_EP<br />
   INDEX (UNIQUE SCAN)          UQ_T_EP<br />
TKPROF<br />
If you want to know, how much time an SQL statement acutally used, use TKPROF </p>
<p>References</p>
<p>-	http://www.evolt.org/node/2986<br />
Adam Patrick, Use Oracle&#8217;s Explain Plan to Tune Your Queries, August 24, 2000<br />
-	http://www.adp-gmbh.ch/ora/explainplan.html</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/enginozer.wordpress.com/58/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/enginozer.wordpress.com/58/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/enginozer.wordpress.com/58/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/enginozer.wordpress.com/58/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/enginozer.wordpress.com/58/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/enginozer.wordpress.com/58/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/enginozer.wordpress.com/58/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/enginozer.wordpress.com/58/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/enginozer.wordpress.com/58/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/enginozer.wordpress.com/58/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=58&subd=enginozer&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://enginozer.wordpress.com/2009/09/25/oracle-explain-plan/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d115faa5b1011c2837cb2de5b694342f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">enginozer</media:title>
		</media:content>
	</item>
		<item>
		<title>Execute Immediate</title>
		<link>http://enginozer.wordpress.com/2009/08/14/execute-immediate/</link>
		<comments>http://enginozer.wordpress.com/2009/08/14/execute-immediate/#comments</comments>
		<pubDate>Fri, 14 Aug 2009 05:51:00 +0000</pubDate>
		<dc:creator>Engin ÖZER</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://enginozer.wordpress.com/?p=53</guid>
		<description><![CDATA[EXECUTE IMMEDIATE StatementThe EXECUTE IMMEDIATE statement executes a dynamic SQL statement or anonymous PL/SQL block. You can use it to issue SQL statements that cannot be represented directly in PL/SQL, or to build up statements where you do not know all the table names, WHERE clauses, and so on in advance. For more information, see [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=53&subd=enginozer&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>EXECUTE IMMEDIATE StatementThe EXECUTE IMMEDIATE statement executes a dynamic SQL statement or anonymous PL/SQL block. You can use it to issue SQL statements that cannot be represented directly in PL/SQL, or to build up statements where you do not know all the table names, WHERE clauses, and so on in advance. For more information, see &#8220;Using the EXECUTE IMMEDIATE Statement in PL/SQL&#8221;.</p>
<p>Syntax</p>
<p>Description of the illustration execute_immediate_statement.gif</p>
<p>Keyword and Parameter Description</p>
<p>bind_argument</p>
<p>An expression whose value is passed to the dynamic SQL statement, or a variable that stores a value returned by the dynamic SQL statement.</p>
<p>BULK COLLECT</p>
<p>Stores result values in one or more collections, for faster queries than loops with FETCH statements. For more information, see &#8220;Reducing Loop Overhead for DML Statements and Queries with Bulk SQL&#8221;.</p>
<p>collection_name</p>
<p>A declared collection into which select_item values are fetched. For each select_item, there must be a corresponding, type-compatible collection in the list.</p>
<p>host_array_name</p>
<p>An array (declared in a PL/SQL host environment and passed to PL/SQL as a bind variable) into which select_item values are fetched. For each select_item, there must be a corresponding, type-compatible array in the list. Host arrays must be prefixed with a colon.</p>
<p>define_variable</p>
<p>A variable that stores a selected column value.</p>
<p>dynamic_string</p>
<p>A string literal, variable, or expression that represents a single SQL statement or a PL/SQL block. It must be of type CHAR or VARCHAR2, not NCHAR or NVARCHAR2.</p>
<p>INTO &#8230;</p>
<p>Used only for single-row queries, this clause specifies the variables or record into which column values are retrieved. For each value retrieved by the query, there must be a corresponding, type-compatible variable or field in the INTO clause.</p>
<p>record_name</p>
<p>A user-defined or %ROWTYPE record that stores a selected row.</p>
<p>returning_clause</p>
<p>Returns values from inserted rows, eliminating the need to SELECT the rows afterward. You can retrieve the column values into variables or into collections. You cannot use the RETURNING clause for remote or parallel inserts. If the statement does not affect any rows, the values of the variables specified in the RETURNING clause are undefined. For the syntax of returning_clause, see the &#8220;RETURNING INTO Clause&#8221;.</p>
<p>USING &#8230;</p>
<p>Specifies a list of input and/or output bind arguments. The parameter mode defaults to IN.</p>
<p>Usage Notes</p>
<p>Except for multi-row queries, the dynamic string can contain any SQL statement (without the final semicolon) or any PL/SQL block (with the final semicolon). The string can also contain placeholders for bind arguments. You cannot use bind arguments to pass the names of schema objects to a dynamic SQL statement.</p>
<p>You can place all bind arguments in the USING clause. The default parameter mode is IN. For DML statements that have a RETURNING clause, you can place OUT arguments in the RETURNING INTO clause without specifying the parameter mode, which, by definition, is OUT. If you use both the USING clause and the RETURNING INTO clause, the USING clause can contain only IN arguments.</p>
<p>At run time, bind arguments replace corresponding placeholders in the dynamic string. Every placeholder must be associated with a bind argument in the USING clause and/or RETURNING INTO clause. You can use numeric, character, and string literals as bind arguments, but you cannot use Boolean literals (TRUE, FALSE, and NULL). To pass nulls to the dynamic string, you must use a workaround. See &#8220;Passing Nulls to Dynamic SQL&#8221;.</p>
<p>Dynamic SQL supports all the SQL datatypes. For example, define variables and bind arguments can be collections, LOBs, instances of an object type, and refs. Dynamic SQL does not support PL/SQL-specific types. For example, define variables and bind arguments cannot be BOOLEANs or index-by tables. The only exception is that a PL/SQL record can appear in the INTO clause.</p>
<p>You can execute a dynamic SQL statement repeatedly using new values for the bind arguments. You still incur some overhead, because EXECUTE IMMEDIATE re-prepares the dynamic string before every execution.</p>
<p>The string argument to the EXECUTE IMMEDIATE command cannot be one of the national character types, such as NCHAR or NVARCHAR2.</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/enginozer.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/enginozer.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/enginozer.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/enginozer.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/enginozer.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/enginozer.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/enginozer.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/enginozer.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/enginozer.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/enginozer.wordpress.com/53/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=53&subd=enginozer&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://enginozer.wordpress.com/2009/08/14/execute-immediate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d115faa5b1011c2837cb2de5b694342f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">enginozer</media:title>
		</media:content>
	</item>
		<item>
		<title>Using Java At Oracle DB</title>
		<link>http://enginozer.wordpress.com/2009/07/29/using-java-at-oracle-db/</link>
		<comments>http://enginozer.wordpress.com/2009/07/29/using-java-at-oracle-db/#comments</comments>
		<pubDate>Wed, 29 Jul 2009 10:50:46 +0000</pubDate>
		<dc:creator>Engin ÖZER</dc:creator>
				<category><![CDATA[Oracle Java]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Java at DB]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Oracle Java Example]]></category>

		<guid isPermaLink="false">http://enginozer.wordpress.com/?p=44</guid>
		<description><![CDATA[Oracle has presented us so many libraries that we can use in order to accomplish our tasks. But, sometimes you need more. Because of this reason Oracle give Java support. You can use your Java classes at Oracle pl/sql scripts. As an example please look at following code sections;
Giving Grants;
Firstly, you have to give Java [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=44&subd=enginozer&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Oracle has presented us so many libraries that we can use in order to accomplish our tasks. But, sometimes you need more. Because of this reason Oracle give Java support. You can use your Java classes at Oracle pl/sql scripts. As an example please look at following code sections;</p>
<p><strong>Giving Grants;</strong><br />
Firstly, you have to give Java privilidges to your user.</p>
<p>GRANT JAVASYSPRIV TO SOMEUSERNAME;<br />
GRANT JAVAUSERPRIV TO SOMEUSERNAME;</p>
<p><strong>Creating Java Class;</strong></p>
<p>Then after you have to write your java code at DB on Java section. </p>
<p>create or replace and compile java source named engin as<br />
public class deneme<br />
{<br />
    public static String entry(String x)<br />
  {<br />
    return &#8220;engin_&#8221; + x;<br />
  }<br />
}</p>
<p><strong>Registering Java Class</strong></p>
<p>This code registers our Java Class function deneme.entry as firstjava on pl/sql</p>
<p>CREATE OR REPLACE FUNCTION firstjava (<br />
   file IN VARCHAR2) RETURN VARCHAR2<br />
AS LANGUAGE JAVA<br />
   NAME &#8216;deneme.entry(java.lang.String)<br />
            return java.lang.String&#8217;;</p>
<p><strong>Example Procedure</strong></p>
<p>CREATE OR REPLACE Procedure engin_tesst<br />
aa varchar2(100);<br />
IS<br />
   begin<br />
   aa:=firstjava(&#8216;c:\temp\temp.sql&#8217;);<br />
   dbms_output.put_line(aa);<br />
END;</p>
<p><strong>Test Script</strong></p>
<p>begin<br />
engin_tesst;<br />
end;</p>
<p><strong>Result: </strong>c:\temp\temp.sqlaaa</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/enginozer.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/enginozer.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/enginozer.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/enginozer.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/enginozer.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/enginozer.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/enginozer.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/enginozer.wordpress.com/44/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/enginozer.wordpress.com/44/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/enginozer.wordpress.com/44/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=44&subd=enginozer&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://enginozer.wordpress.com/2009/07/29/using-java-at-oracle-db/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d115faa5b1011c2837cb2de5b694342f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">enginozer</media:title>
		</media:content>
	</item>
		<item>
		<title>INTRODUCTION TO J2ME</title>
		<link>http://enginozer.wordpress.com/2009/07/20/introduction-to-j2me/</link>
		<comments>http://enginozer.wordpress.com/2009/07/20/introduction-to-j2me/#comments</comments>
		<pubDate>Mon, 20 Jul 2009 07:33:48 +0000</pubDate>
		<dc:creator>Engin ÖZER</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[CLDC]]></category>
		<category><![CDATA[J2ME]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[Mobile Phone]]></category>
		<category><![CDATA[Phone]]></category>

		<guid isPermaLink="false">http://enginozer.wordpress.com/?p=37</guid>
		<description><![CDATA[What is J2ME?
J2ME stands for Java 2, Micro Edition. It is a stripped-down version of Java targeted at devices which have limited processing power and storage capabilities and intermittent or fairly low-bandwidth network connections. These include mobile phones, pagers,wireless devices and set-top boxes among others.
A Sample Wireless Stack would consist of:

Profiles
Configurations
Java Virtual Machines
Host Operating System

What [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=37&subd=enginozer&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><h2>What is J2ME?</h2>
<p>J2ME stands for Java 2, Micro Edition. It is a stripped-down version of Java targeted at devices which have limited processing power and storage capabilities and intermittent or fairly low-bandwidth network connections. These include mobile phones, pagers,wireless devices and set-top boxes among others.</p>
<p>A Sample Wireless Stack would consist of:</p>
<ul>
<li>Profiles</li>
<li>Configurations</li>
<li>Java Virtual Machines</li>
<li>Host Operating System</li>
</ul>
<h3>What is a J2ME Configuration?</h3>
<p>A configuration defines the minimum Java technology that an application developer can expect on a broad range of implementing devices.</p>
<h4>J2ME Connected, Limited Device Configuration (CLDC)</h4>
<ul type="square">
<li>specifies the Java environment for mobile phone, pager and wireless devices</li>
<li>CLDC devices are usually wireless</li>
<li>160 &#8211; 512k of memory available for Java</li>
<li>typically has limited power or battery operated</li>
<li>network connectivity, often wireless, intermittent, low-bandwidth (9600bps or less)</li>
</ul>
<h4>J2ME Connected Device Configuration (CDC)</h4>
<ul type="square">
<li>describes the Java environment for digital television set-top boxes, high end wireless devices and automotive telematics systems.</li>
<li>device is powered by a 32-bit processor</li>
<li>2MB or more of total memory available for Java</li>
<li>network connectivity, often wireless, intermittent, low-bandwidth (9600bps or less)</li>
</ul>
<p>These two configurations differ only in their respective memory and display capabilities.</p>
<h3>What is a J2ME Profile?</h3>
<p>A specification layer above the configuration which describes the Java configuration for a specific vertical market or device type.</p>
<h3>J2ME Profiles</h3>
<h4>J2ME Mobile Information Device Profile (MIDP)</h4>
<ul type="square">
<li>this is the application environment for wireless devices based on the CLDC</li>
<li>contains classes for user interface, storage and networking</li>
</ul>
<h4>J2ME Foundation Profile, Personal Basis, Personal and RMI profiles</h4>
<ul type="square">
<li>these are profiles for devices based on the CDC, which are not addressed in this tutorial</li>
</ul>
<h3>Virtual Machines</h3>
<p>The CLDC and the CDC each require their own virtual machine because of their different memory and display capabilities. The CLDC virtual machine is far smaller than that required by the CDC and supports less features. The virtual machine for the CLDC is called the Kilo Virtual Machine (KVM) and the virtual machine for the CDC is called the CVM.</p>
<p>Tools</p>
<p> </p>
<p>First make sure that you have the Java 2 SDK, Standard Edition (J2SE SDK), version 1.4.2 (or later). This is essential for development. If you haven&#8217;t installed it, download it and install it from here <a href="http://java.sun.com/j2se/downloads/index.html">http://java.sun.com/j2se/downloads/index.html</a>.<br />
You absolutely MUST have the J2SE SDK installed before you install the Java Wireless Toolkit as you will be needing the tools it contains (such as javac) to compile and run your MIDlets.</p>
<p>Then download the J2ME Wireless Toolkit (WTK) which is available free from Sun here &#8211; <a href="http://java.sun.com/products/j2mewtoolkit/">http://java.sun.com/products/j2mewtoolkit/</a>. I&#8217;m going to assume that you&#8217;ll be installing this in the <em>C:\j2mewtk\ </em>directory, if you use another directory, just modify the paths accordingly.</p>
<h4>Paths</h4>
<p>Java needs to know where all your files are, so we need to add the location of the Java binaries to the system path.</p>
<h4>Windows 95/98</h4>
<p>Go to Start-&gt;Run. Type in <em>command</em>. Then type</p>
<p>SET PATH=%PATH%;C:\j2mewtk\bin</p>
<p>You should also edit your C:\autoexec.bat file to include this line, so you don&#8217;t have to enter it every single time you restart your computer. After you&#8217;ve done this, you should be able to run the tools included in the Java Wireless Toolkit from any directory on your system.</p>
<h4>Windows 2000/XP</h4>
<ul>
<li>Go to Control Panel -&gt; System.</li>
<li>Click on the Advanced Tab</li>
<li>Click on the Environment Variables button</li>
<li>Double-click the PATH variable in the System variables box</li>
<li>At the end of the <em>Variable value</em> field, add the path to your J2ME WTK installation &#8211; for me this is something like <em>C:\j2mewtk</em></li>
<li>If you had to install the J2SE SDK too, it&#8217;s a good idea to add the path for that &#8211; for me this is <em>C:\j2sdk1.4.2_03</em> and <em>C:\j2sdk1.4.2_03\bin</em>. <a name="System Properties" href="http://enginozer.wordpress.com/wp-admin/#this">Here&#8217;s what my screen looked like.</a></li>
</ul>
<p>A good way to test if this worked is to type the preverify command without any arguments in the command line. You should see something like this on your screen.</p>
<p>C:\&gt; preverify<br />
Usage: PREVERIFY.EXE [options] classnames|dirnames &#8230;</p>
<p>where options include:<br />
-classpath<br />
Directories in which to look for classes<br />
-d Directory in which output is written<br />
@ Read command line arguments from a text file.</p>
<p> </p>
<h2>Application Development</h2>
<h3>MIDlets vs Applets</h3>
<p>MIDlets are applets for mobile phones. Just like applets, they run in a protected sandbox &#8211; the KVM &#8211; but unlike applets, they are extremely limited. MIDP 1.0 is currently found on most Java-capable phones and is fairly restrictive. As an example &#8211; the KVM doesn&#8217;t allow you to process floating point numbers yet and MIDlets written for MIDP 1.0 can&#8217;t access anything outside of the sandbox without proprietary APIs from phone manufacturers. So, put your dreams of developing the ultimate MIDlet with hooks into every part of your phone OS on the backburner for a while. If you want to find out exactly how limited MIDP 1.0 is, you should probably <a name="MIDP 1.0 Spec" href="http://www.jcp.org/aboutJava/communityprocess/final/jsr037/">read the spec here. </a>Once you&#8217;ve done that you might want to check out  with that spec. For the time being we&#8217;re going to write our first MIDlet &#8211; a full-featured &#8220;Hello MIDlet&#8221; application.</p>
<h3>Simple HelloMIDlet</h3>
<p>We&#8217;re going to use a program called Ktoolbar from the JAVA WTK which we installed earlier.</p>
<ul>
<li>Go to Start-&gt;Programs-&gt;J2ME Wireless Toolkit 2.1-&gt;KToolbar.</li>
<li>Click on the <em>New Project</em> button and name your project <em>HelloProject</em> and your MIDlet <em>HelloMidlet</em>. <a href="http://enginozer.wordpress.com/wp-admin/#this">You should see something like this. </a></li>
<li>Once you press Create Project, KToolbar will create a bunch of directories for your project in the apps subdirectory. We&#8217;re going to ignore most of them for the moment and focus on a few important onesC:\j2mewtk\apps\HelloProject <strong>- the main directory for your project</strong><br />
C:\j2mewtk\apps\HelloProject\bin <strong>- where Ktoolbar stores .jar, .jar and manifest.mf files </strong><br />
C:\j2mewtk\apps\HelloProject\classes <strong>- where the class files are stored</strong><br />
C:\j2mewtk\apps\HelloProject\src <strong>- where the source .java files are stored</strong></li>
<li>Now, fire up your favourite text editor &#8211; I like <a name="Textpad" href="http://www.textpad.com/" target="_blank">Textpad</a>- and type in the following code/* Hello Midlet &#8211; your first program*/<br />
import javax.microedition.lcdui.*;<br />
import javax.microedition.midlet.*;public class HelloMidlet<br />
extends MIDlet<br />
implements CommandListener {<br />
private Form mMainForm;</p>
<p>public HelloMidlet() {<br />
mMainForm = new Form(&#8220;HelloMidlet&#8221;);<br />
mMainForm.append(new StringItem(null, &#8220;Hello, MIDP! \n\nYou and me &#8211; we&#8217;re gonna make sweet MIDlets together! &#8220;));<br />
mMainForm.addCommand(new Command(&#8220;Exit&#8221;, Command.EXIT, 0));<br />
mMainForm.setCommandListener(this);<br />
}</p>
<p>public void startApp() {<br />
Display.getDisplay(this).setCurrent(mMainForm);<br />
}</p>
<p>public void pauseApp() {}</p>
<p>public void destroyApp(boolean unconditional) {}</p>
<p>public void commandAction(Command c, Displayable s) {<br />
notifyDestroyed();<br />
}<br />
}</li>
<li>Save this file as HelloMidlet.java in the <em>C:\j2mewtk\apps\HelloProject\src </em></li>
<li>Go back to KToolBar &#8211; then click on Build and then Run &#8211; you should see <a name="HelloMidlet" href="http://enginozer.wordpress.com/wp-admin/#this">something like this.</a></li>
<li>Click on the Launch softkey in the emulator to get your MIDlet to say hello. You&#8217;ve just written your first MIDlet!</li>
</ul>
<p> </p>
<h2>Provisioning</h2>
<h3>Okay, now how do I get my code onto my phone?</h3>
<p>Once you&#8217;ve created your lovely little MIDlet and ensured that everything worked smoothly in the emulator, the next step is to get it running on an actual device. <em>Provisioning</em> is the name given to the process of deploying your application in such a way that it is easily downloaded and installed on the device.</p>
<h4>1. Over The Air (OTA) Provisioning</h4>
<p>OTA provisioning allows users to download your application wirelessly using the WAP browsers built into their phones. To begin, we need to take a look at the Java Application Descriptor (JAD) file that is created when you package a MIDlet using the J2ME Wireless Toolkit. The JAD file stores information about your application and lets you modify various parameters of the MIDlet suite such as where the icon resource can be found, which MIDlets are included and where you can download the full version of the application. To edit a JAD file using the Wireless Toolkit, open your project, then click on <em>Settings</em>. This will open up a new window with a number of tabs &#8211; API Selection, Required, Optional, User Defined, MIDlets, Push Registry and Permissions.</p>
<ol>
<li>API SelectionThis is where you choose which version of MIDP your application will use and which optional packages (JSRs) are included. The default is set to JTWI (Java Technology for the Wireless Industry) which allows you to use MIDP 2.0 as well as MMAPI and other exciting things. If you&#8217;re having any problems with your application on your device try changing this to MIDP 1.0.</li>
<li>RequiredThis tab includes various options which are essential for packaging a MIDlet suite. The <em>MIDlet-Jar-URL</em> attribute is where we will define the location of the packaged JAR file to be downloaded to the device.</li>
<li>OptionalThis tab includes optional parameters for your MIDlet &#8211; such as the path to the icon for the entire suite, a description and a <em>MIDlet-Info-URL </em>parameter.</li>
<li>User DefinedThis tab includes user defined variables that your MIDlet can use &#8211; such as a common URL that you don&#8217;t want to hard wire into the source code.</li>
<li>MIDletsThis tab manages all the settings for the MIDlets within your suite. At the very least you need to have one file here. This is also where you set the path to the MIDlet&#8217;s icon resource.</li>
<li>Push RegistryThis lets you configure the Push Registry which allows your MIDlet to listen and act on information received from a remote source. MIDP 2.0 Only.</li>
<li>PermissionsUnder MIDP 1.0, applications could only access libraries packaged inside the suite &#8211; this was called the <em>sandbox model</em>. MIDP 2.0 introduces the concept of <em>trusted applications</em> which allow access beyond the sandbox. This section allows you to specify which APIs are accessible.</li>
</ol>
<p>For our purposes &#8211; the most important property is the <em>MIDlet-Jar-URL</em> within the Required tab. Here are the steps you need to take:</p>
<ol>
<li>Create a folder on your web serverHopefully you have an account with a web provider &#8211; login to that account and create a directory for your MIDlets to live and be served from. I created the directory <em><a href="http://uberthings.com/mobile/midlets" target="_blank">http://uberthings.com/mobile/midlets</a></em>. Once you&#8217;ve got that, you need to make a few changes to allow your server (assumed to be Apache) to serve JAD and JAR files correctly. Go to the root of your account and edit or create your <em>.htaccess</em> file. Add these lines:AddType text/vnd.sun.j2me.app-descriptor jad<br />
AddType application/java-archive jar</p>
<p>Save this file. If you&#8217;re not using Apache, ensure that your MIME types include the above two settings.</li>
<li>Specify the <em>MIDlet-Jar-URL</em>Click on Settings then go to the Required Tab. In the <em>MIDlet-Jar-URL</em> field, fill in the absolute URL of your JAR file. This will normally be something like <em>http://mydomain/mydir/HelloProject.jar</em>. For my server, this was <em>http://www.uberthings.com/mobile/midlets/HelloProject.jar</em>.</li>
<li>Package your MIDletClick on Project-&gt;Package-&gt;Create Package. This will create a .jar and a .jad file in your applications bin folder. For my application &#8211; this was <em>c:\j2mewtk\apps\HelloProject\bin\HelloProject.jar</em> and <em>c:\j2mewtk\apps\HelloProject\bin\HelloProject.jad</em>.</li>
<li>Upload the packaged MIDlet suiteUpload the JAR and JAD files that the packaging operation created to the folder you created earlier.</li>
<li>Test with your deviceOpen the WAP browser on your phone and point it to the URL of the JAD file. Using my example, this would be <em>http://uberthings.com/mobile/midlets/HelloProject.jad</em>. Your device should then prompt you to download and install the MIDlet. Carry it around and show it off to all your friends!</li>
</ol>
<h4>2. Cable / Bluetooth</h4>
<p>If you&#8217;ve got a Bluetooth adaptor or a USB cable which connects directly to your phone, you can use this to quickly test your packaged midlet.</p>
<p><strong>Windows XP/2000</strong>: Browse to the bin folder of your project, right click on the .jar file and select Send To-&gt;Bluetooth-&gt;YOURDEVICE.<br />
<strong>MacOS X</strong>: Click on the Bluetooth icon in the menu bar, choose Send File. Send it to your device.<br />
This should send a message to your phone which will install the MIDlet once opened. This should work on most Nokia Series 60 phones (3650, 6600, N-Gage etc).</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/enginozer.wordpress.com/37/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/enginozer.wordpress.com/37/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/enginozer.wordpress.com/37/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/enginozer.wordpress.com/37/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/enginozer.wordpress.com/37/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/enginozer.wordpress.com/37/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/enginozer.wordpress.com/37/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/enginozer.wordpress.com/37/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/enginozer.wordpress.com/37/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/enginozer.wordpress.com/37/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=37&subd=enginozer&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://enginozer.wordpress.com/2009/07/20/introduction-to-j2me/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d115faa5b1011c2837cb2de5b694342f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">enginozer</media:title>
		</media:content>
	</item>
		<item>
		<title>Using Clob values at dynamic SQL</title>
		<link>http://enginozer.wordpress.com/2009/07/10/using-clob-values-at-dynamic-sql/</link>
		<comments>http://enginozer.wordpress.com/2009/07/10/using-clob-values-at-dynamic-sql/#comments</comments>
		<pubDate>Fri, 10 Jul 2009 14:38:54 +0000</pubDate>
		<dc:creator>Engin ÖZER</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[CLOB]]></category>
		<category><![CDATA[DBMS_SQL]]></category>
		<category><![CDATA[Insert]]></category>

		<guid isPermaLink="false">http://enginozer.wordpress.com/?p=26</guid>
		<description><![CDATA[Today, i had a problem while trying to use a clob value at my dynamic sql. Let me explain the problem further;
Development IDE : Oracle Forms
Failed Function: forms_ddl
I was trying to give forms_ddl function a clob value which includes &#8216;insert into &#8230;_table (&#8230;) values(&#8230;)&#8217; format insert sql. Everything was working fine. But then i had [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=26&subd=enginozer&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Today, i had a problem while trying to use a clob value at my dynamic sql. Let me explain the problem further;</p>
<p>Development IDE : Oracle Forms</p>
<p>Failed Function: forms_ddl</p>
<p>I was trying to give forms_ddl function a clob value which includes &#8216;insert into &#8230;_table (&#8230;) values(&#8230;)&#8217; format insert sql. Everything was working fine. But then i had to insert a clob value that is more than 4000 character(As you know the biggest varchar2 value can be 4000 characters), then it failed to insert. I had a lot of research about this and i found out the problem lying behind it. It was the character limit. Forms_ddl function only takes 4000 character of sql and truncates if it comes more than 4000. </p>
<p>So, after researching i found out a usage which i will share with you. Please take a careful look at the code section below.</p>
<p>declare</p>
<p>   c3 integer;</p>
<p>   c3_tmp integer;</p>
<p>   str varchar2(4000);</p>
<p>   tmp clob;&#8211; the value to be inserted</p>
<p>begin </p>
<p>  c3 := dbms_sql.open_cursor;&#8211; opens a cursor for us to execute our sql command<br />
  <br />
  <br />
  dbms_sql.parse(c3, str, 1);&#8211; this statement parses our sql. str is the parameter which our sql statements included.   </p>
<p>    &#8211;Other parameters can be used same.<br />
 </p>
<p>  dbms_sql.bind_variable(c3, &#8216;:values&#8217;, tmp);&#8211;binding variable :values into our dynamic sql and telling Oracle  &#8212;&#8212;&#8212;&#8211;that :values := tmp. By the help of this statement we do not have to write all the clob value into our dynamic sql. So &#8212;no character limit will effect this statement.</p>
<p>  c3_tmp := dbms_sql.execute(c3);&#8211; This statement executes our sql. Everything works fine.</p>
<p>  commit;</p>
<p>end;</p>
<p> </p>
<p>&#8211;str is the string which is like &#8216;insert into &#8230; (column_names) values(values&#8211;but one of them is a clob value which is declared like a bind variable :values)&#8217;</p>
<p>example;</p>
<p>str := &#8216;insert into users_table (op_id,PlacesVisited) values (&#8216;EOZER&#8217;,:values)&#8217;</p>
<p>this sql statement script can be used to insert user_table a clob value with <strong>bind variable.</strong></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/enginozer.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/enginozer.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/enginozer.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/enginozer.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/enginozer.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/enginozer.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/enginozer.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/enginozer.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/enginozer.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/enginozer.wordpress.com/26/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=26&subd=enginozer&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://enginozer.wordpress.com/2009/07/10/using-clob-values-at-dynamic-sql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d115faa5b1011c2837cb2de5b694342f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">enginozer</media:title>
		</media:content>
	</item>
		<item>
		<title>Oracle Date Time Functions</title>
		<link>http://enginozer.wordpress.com/2009/06/29/oracle-date-time-functions/</link>
		<comments>http://enginozer.wordpress.com/2009/06/29/oracle-date-time-functions/#comments</comments>
		<pubDate>Mon, 29 Jun 2009 10:46:46 +0000</pubDate>
		<dc:creator>Engin ÖZER</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Date]]></category>
		<category><![CDATA[Date Time Functions]]></category>
		<category><![CDATA[Time]]></category>

		<guid isPermaLink="false">http://enginozer.wordpress.com/?p=14</guid>
		<description><![CDATA[SYSDATE
Sysdate represents current date and time in Oracle. 
Example;
select sysdate from dual
Result;
29/06/2009 1:41:10 PM
 
ADD_MONTHS
This function adds specified amount of months to date given. Its usage and results are like this;
declare
  x date;
begin
           x  :=  &#8217;25/10/2009&#8242;;
           x := add_months(x,1);
           dbms_output.putline(x);
end;
Result;
25/11/2009
 
MONTHS_BETWEEN

This function is used to get the months between two date values given. The only detail with this function [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=14&subd=enginozer&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><strong>SYSDATE</strong></p>
<p>Sysdate represents current date and time in Oracle. </p>
<p>Example;</p>
<p>select sysdate from dual</p>
<p><strong>Result;</strong></p>
<p>29/06/2009 1:41:10 PM</p>
<p> </p>
<p><strong>ADD_MONTHS</strong></p>
<p>This function adds specified amount of months to date given. Its usage and results are like this;</p>
<p>declare</p>
<p>  x date;</p>
<p>begin</p>
<p>           x  :=  &#8217;25/10/2009&#8242;;</p>
<p>           x := add_months(x,1);</p>
<p>           dbms_output.putline(x);</p>
<p>end;</p>
<p><strong>Result;</strong></p>
<p>25/11/2009</p>
<p> </p>
<p><strong>MONTHS_BETWEEN<br />
</strong></p>
<p>This function is used to get the months between two date values given. The only detail with this function is that this function returns a float value. Because of this reason you can either use this value directly, truncate it, floor it, ceil it or round it. It is up to your usage.</p>
<p>Example;</p>
<p>select months_between(&#8216;25/10/2009&#8242;,&#8217;26/12/2009&#8242;) from dual</p>
<p><strong>Result;</strong></p>
<p>-1.03225806451613</p>
<p>This value tells us that first date is past according to second date and more than one months are between these dates.</p>
<p> </p>
<p><strong>Date Format</strong></p>
<p>To change the date format of our session we can use this Oracle DB command;</p>
<p>ALTER SESSION SET NLS_DATE_FORMAT = &#8216;DD/mm/YYYY HH24:MI:SS&#8217;;</p>
<p>This code changes our date time format to example given;</p>
<p><strong>Result</strong></p>
<p>25/10/2009 15:12:42</p>
<p><strong>Date Formats Ex</strong></p>
<p>There are so many date formats at Oracle that can be used. If you ask why we need this formats it is clear for me to say that you will absolutely need this formats in order to show your values correctly to en user.</p>
<p>You could want to show current date like this; &#8216;25/10/2009&#8242; or like this &#8216;25-10-2009&#8242; or just with numbers &#8216;25102009&#8242;. Every companies has their own styles of coding. Date formats are one of them. One company could tell you that they want you to show every dates at dd/mm/yyyy format.  If you do not format your dates each time you parse it to this format it can work fine at first. But, whenever someone tries to change machine&#8217;s NLS settings to another values then you are having problem. To avoid this kind of situations you should be using date formats for following situations;</p>
<p>        &#8211; When you are parsing date value to a string value (varchar&#8230;);</p>
<p>                 * You can use to_char(date,&#8217;format&#8217;)&#8211;date and format are in varchar format.</p>
<p>                 example;</p>
<p>                 select to_char(sysdate,&#8217;dd/mm,yyyy&#8217;) from dual;</p>
<p><strong>                 Retuns</strong></p>
<p>                  29/06,2009</p>
<p>                 Example 2</p>
<p>                 select to_char(sysdate,&#8217;day-mon-year&#8217;) from dual</p>
<p><strong>                 Retuns</strong></p>
<p><strong> </strong>                mon-june-two thousand nine</p>
<p>                </p>
<p>                   You can convert your date values at any format you want. As in the second example you can convert date values to human language format.  It takes this formats from NLS(Language) settings.</p>
<p> </p>
<p>           &#8211; When you want to convert char to date;</p>
<p>                    * You can use to_date function</p>
<p>                     Example</p>
<p>                     declare</p>
<p>                           x date;</p>
<p>                     begin</p>
<p>                             x := to_date(&#8216;25/10/2009&#8242;,&#8217;dd/mm/yyy&#8217;) ;</p>
<p>                     end;</p>
<p><strong>                     Warning:</strong> Although Oracle recognises your computer&#8217;s date format automatically to keep your software portable you should specify format parameter each time you use it.</p>
<p><strong>NEXT_DAY</strong></p>
<p>This function returns the first date that the day of week specified comes.</p>
<p>Example;</p>
<p><span style="font-size:x-small;color:#008080;"><span style="font-size:x-small;color:#008080;"><span style="font-size:x-small;color:#008080;"><span style="font-size:x-small;color:#008080;">SELECT </span></span></span></span><span style="font-size:x-small;color:#000080;"><span style="font-size:x-small;color:#000080;">NEXT_DAY(</span></span><span style="font-size:x-small;color:#0000ff;"><span style="font-size:x-small;color:#0000ff;">&#8216;27/06/2009&#8242;</span></span><span style="font-size:x-small;color:#000080;"><span style="font-size:x-small;color:#000080;">, &#8216;</span></span><span style="font-size:x-small;color:#0000ff;"><span style="font-size:x-small;color:#0000ff;">MON&#8217;</span></span><span style="font-size:x-small;color:#000080;"><span style="font-size:x-small;color:#000080;">) </span></span><span style="font-size:x-small;color:#008080;"><span style="font-size:x-small;color:#008080;">FROM</span></span><span style="font-size:x-small;color:#000080;"><span style="font-size:x-small;color:#000080;"> dual;</span></span></p>
<p><span style="color:#000080;"><strong>Returns</strong></span></p>
<p><span style="color:#000080;">29/06/2009</span></p>
<p> </p>
<p><strong>ROUND</strong></p>
<p><strong> </strong><br />
This function round the date value given. It uses the standard rounding rules. Rounds to nearest date.</p>
<p>Example</p>
<p><span style="font-size:x-small;color:#008080;"><span style="font-size:x-small;color:#008080;"><span style="font-size:x-small;color:#008080;"><span style="font-size:x-small;color:#008080;">SELECT<span style="font-size:x-small;color:#008080;"><span style="font-size:x-small;color:#008080;"><span style="font-size:x-small;color:#008080;"><span style="font-size:x-small;color:#008080;"><span style="font-size:x-small;color:#008080;"><span style="font-size:x-small;color:#008080;"> </span></span></span></span></span></span></span></span></span></span><span style="font-size:x-small;color:#000080;"><span style="font-size:x-small;color:#000080;">ROUND(TO_DATE(</span></span><span style="font-size:x-small;color:#0000ff;"><span style="font-size:x-small;color:#0000ff;">&#8216;27-11-01&#8242;</span></span><span style="font-size:x-small;color:#000080;"><span style="font-size:x-small;color:#000080;">),</span></span><span style="font-size:x-small;color:#0000ff;"><span style="font-size:x-small;color:#0000ff;">&#8216;mm&#8217;</span></span><span style="font-size:x-small;color:#000080;"><span style="font-size:x-small;color:#000080;">) NEW_YEAR </span></span><span style="font-size:x-small;color:#008080;"><span style="font-size:x-small;color:#008080;">from</span></span><span style="font-size:x-small;color:#000080;"><span style="font-size:x-small;color:#000080;"> dual</span></span></p>
<p> </p>
<p><span style="color:#000080;"><strong>Returns</strong></span></p>
<p><span style="color:#000080;">01/12/0001</span></p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/enginozer.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/enginozer.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/enginozer.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/enginozer.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/enginozer.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/enginozer.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/enginozer.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/enginozer.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/enginozer.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/enginozer.wordpress.com/14/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=14&subd=enginozer&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://enginozer.wordpress.com/2009/06/29/oracle-date-time-functions/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d115faa5b1011c2837cb2de5b694342f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">enginozer</media:title>
		</media:content>
	</item>
		<item>
		<title>Debugging on pl/sql developer</title>
		<link>http://enginozer.wordpress.com/2009/06/22/debugging-on-plsql-developer/</link>
		<comments>http://enginozer.wordpress.com/2009/06/22/debugging-on-plsql-developer/#comments</comments>
		<pubDate>Mon, 22 Jun 2009 19:03:51 +0000</pubDate>
		<dc:creator>Engin ÖZER</dc:creator>
				<category><![CDATA[PL/SQL Developer]]></category>
		<category><![CDATA[Analyse]]></category>
		<category><![CDATA[Debug]]></category>
		<category><![CDATA[pl/sql]]></category>

		<guid isPermaLink="false">http://enginozer.wordpress.com/?p=10</guid>
		<description><![CDATA[Hello,
This is my first post on wordpress. I want to tell you about how to do debugging stuff on pl/sql developer at Oracle database.
Firstly, a database is needed to be connected. To do this, we have to add tns file at our C:\DevSuite10g\NETWORK\ADMIN\tnsnames.ora location. After making sure the tns file is correctly placed there, we [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=10&subd=enginozer&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Hello,</p>
<p>This is my first post on wordpress. I want to tell you about how to do debugging stuff on pl/sql developer at Oracle database.</p>
<p>Firstly, a database is needed to be connected. To do this, we have to add tns file at our C:\DevSuite10g\NETWORK\ADMIN\tnsnames.ora location. After making sure the tns file is correctly placed there, we can start working on pl/sql developer.</p>
<p>Open pl/sql developer program, select the database to connect, write your user id and password then click connect.</p>
<p>congratulations! You have successfully connected to database. You have two ways to open debug window. But i will tell you one. Click on the new button(with sheet picture at bottom of page), it shows a menu then select test window. Write down your code there then click start debuggin button. Program will work line by line. then you can implement your classical style debugging there.</p>
<p>The main diffrence between debugging on normal programming languages and pl/sql is that, at pl/sql you have to make sure what all the select statements returns. Because of this reason while debugging, get all the sql statement&#8217;s and its subqueries&#8217; return values and calculate them correctly.</p>
<p>Don&#8217;t forget, the biggest mistakes at pl/sql programs are made by mistaken select statements.</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/enginozer.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/enginozer.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/enginozer.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/enginozer.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/enginozer.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/enginozer.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/enginozer.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/enginozer.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/enginozer.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/enginozer.wordpress.com/10/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=enginozer.wordpress.com&blog=2597612&post=10&subd=enginozer&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://enginozer.wordpress.com/2009/06/22/debugging-on-plsql-developer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/d115faa5b1011c2837cb2de5b694342f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">enginozer</media:title>
		</media:content>
	</item>
	</channel>
</rss>