<?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/"
	>

<channel>
	<title>Beautiful Data</title>
	<atom:link href="http://perumal.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://perumal.org</link>
	<description>Data is a precious thing that lives forever.</description>
	<lastBuildDate>Fri, 05 Mar 2010 21:18:01 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Man, Whatis and Apropos</title>
		<link>http://perumal.org/man-whatis-and-apropos/</link>
		<comments>http://perumal.org/man-whatis-and-apropos/#comments</comments>
		<pubDate>Fri, 05 Mar 2010 21:16:14 +0000</pubDate>
		<dc:creator>Ramasundaram Perumal</dc:creator>
				<category><![CDATA[Commands]]></category>
		<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://perumal.org/?p=481</guid>
		<description><![CDATA[Man:
man command formats and displays the on-line manual pages.  If you specify section, man only looks in that  section  of the  manual.  name is normally the name of the manual page, which is typically the name of a command, function, or file. 
$ man whatis
whatis(1)            [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Man:</strong></p>
<p><span style="font-family: courier new,courier;">man</span> command formats and displays the on-line manual pages.  If you specify <span style="font-family: courier new,courier;">section</span>, man only looks in that  section  of the  manual.  name is normally the name of the manual page, which is typically the name of a command, function, or file. </p>
<pre>$ man whatis
whatis(1)                                                            whatis(1)

NAME
       whatis - search the whatis database for complete words.

SYNOPSIS
       whatis keyword ...

DESCRIPTION
       whatis  searches  a set of database files containing short descriptions
       of system commands for keywords and displays the result on the standard
       output.  Only complete word matches are displayed.

       The  whatis database is created using the command /usr/sbin/makewhatis.

AUTHOR
       John W. Eaton was the  original  author  of  man.   Zeyd  M.  Ben-Halim
       released  man  1.2,  and  Andries Brouwer followed up with versions 1.3
       thru 1.5p.  Federico  Lucifredi    is  the  current
       maintainer.

SEE ALSO
       apropos(1), man(1).</pre>
<p><strong>Whatis:</strong></p>
<p><span style="font-family: courier new,courier;">whatis </span>command searches a set of database files containing short descriptions of system commands for keywords and displays the result on the standard output.  Only complete word matches are displayed.</p>
<pre>$ whatis whatis
whatis               (1)  - search the whatis database for complete words</pre>
<p><strong>Apropos:</strong></p>
<p><span style="font-family: courier new,courier;">apropos </span>command searches a set of database files containing short descriptions of system commands for keywords and displays the result on the standard output. You can think apropos as a wrapper for the &#8220;man -k&#8221; command, useful for one knows the action but does not rememeber the actual command. Simply put, as shown in the below example, returns the indicated man pages that include the term &#8220;<em>whatis</em>&#8220;. </p>
<pre>$ apropos whatis
apropos              (1)  - search the whatis database for strings
makewhatis           (8)  - Create the whatis database
man                 (rpm) - A set of documentation tools: man, apropos and whatis.
whatis               (1)  - search the whatis database for complete words</pre>
<p>man, whatis, and apropos are closely related commands that provide similar functionality.</p>
<!-- AdSense Now! V1.83 -->
<!-- Post[count: 2] -->
<div class="adsense adsense-leadout" style="text-align:center;margin: 12px;"><script type="text/javascript"><!--
google_ad_client = "pub-2502327266915326";
/* 728x90 Horizontal Top */
google_ad_slot = "2497834684";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<script type="text/javascript"><!--
google_ad_client = "pub-2502327266915326";
/* 728x90 Horizontal Middle */
google_ad_slot = "6439787866";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<script type="text/javascript"><!--
google_ad_client = "pub-2502327266915326";
/* 728x90 Horizontal Bottom */
google_ad_slot = "4537934502";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></div><div id="crp_related"> </div>]]></content:encoded>
			<wfw:commentRss>http://perumal.org/man-whatis-and-apropos/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL Developer: Database Export Wizard to export DDL and Data as DML</title>
		<link>http://perumal.org/sql-developer-database-export-wizard-to-export-ddl-and-data-as-dml/</link>
		<comments>http://perumal.org/sql-developer-database-export-wizard-to-export-ddl-and-data-as-dml/#comments</comments>
		<pubDate>Sat, 27 Feb 2010 18:10:36 +0000</pubDate>
		<dc:creator>Ramasundaram Perumal</dc:creator>
				<category><![CDATA[SQL Developer]]></category>

		<guid isPermaLink="false">http://perumal.org/?p=472</guid>
		<description><![CDATA[Sometimes, you would want to generate a script that you would like to run repeatedly in many environments for many objects. In such situations, use of Database Export wizard helps you generate DDL and DML (INSERT) script; &#8211; you can select object types, specific objects and filter out or restrict the data exported.


Step1: Source / [...]]]></description>
			<content:encoded><![CDATA[<p>Sometimes, you would want to generate a script that you would like to run repeatedly in many environments for many objects. In such situations, use of Database Export wizard helps you generate DDL and DML (INSERT) script; &#8211; you can select object types, specific objects and filter out or restrict the data exported.</p>
<p><img class="aligncenter size-full wp-image-473" title="SQLDeveloper21_Database_Export _Navigation" src="http://perumal.org/wp-content/uploads/SQLDeveloper21_Database_Export-_Navigation.jpg" alt="" width="501" height="284" /></p>
<ul>
<li><strong>Step1: Source / Destination</strong> – You can choose SQL file location, database connection, and DDL options.</li>
</ul>
<p><img class="aligncenter size-full wp-image-474" title="SQLDeveloper21_ExportWizard_1_of_5" src="http://perumal.org/wp-content/uploads/SQLDeveloper21_ExportWizard_1_of_5.jpg" alt="" width="640" height="480" /></p>
<ul>
<li><strong>Step 2: Types to Export</strong> – You can select the type of objects you want to explore.</li>
</ul>
<p><img class="aligncenter size-full wp-image-475" title="SQLDeveloper21_ExportWizard_2_of_5" src="http://perumal.org/wp-content/uploads/SQLDeveloper21_ExportWizard_2_of_5.jpg" alt="" width="640" height="480" /></p>
<ul>
<li><strong>Step 3: Specify Objects</strong> – You can select the specific object that you need to export.</li>
</ul>
<p><img class="aligncenter size-full wp-image-476" title="SQLDeveloper21_ExportWizard_3_of_5" src="http://perumal.org/wp-content/uploads/SQLDeveloper21_ExportWizard_3_of_5.jpg" alt="" width="640" height="480" /></p>
<ul>
<li><strong>Step 4: Specify Data</strong> – You can apply conditions to data by using a select or filter criteria.</li>
</ul>
<p><img class="aligncenter size-full wp-image-477" title="SQLDeveloper21_ExportWizard_4_of_5" src="http://perumal.org/wp-content/uploads/SQLDeveloper21_ExportWizard_4_of_5.jpg" alt="" width="640" height="480" /></p>
<ul>
<li><strong>Step 5: Export Summary</strong> – At this stage you can review and verify the information list on the summary screen. Once you hit Finish, the SQL script is generated and loaded into SQL Worksheet, ready for you to run on any schema.</li>
</ul>
<p><img class="aligncenter size-full wp-image-478" title="SQLDeveloper21_ExportWizard_5_of_5" src="http://perumal.org/wp-content/uploads/SQLDeveloper21_ExportWizard_5_of_5.jpg" alt="" width="640" height="480" /></p>
<p>Everything looks great, simple and most importantly the tool is free of cost - sample script generated by the wizard is below:</p>
<pre>--------------------------------------------------------
--  File created - Friday-February-26-2010
--------------------------------------------------------
--------------------------------------------------------
--  DDL for Table T1
--------------------------------------------------------

  CREATE TABLE "T1"
   (	"ID" NUMBER
   ) ;

---------------------------------------------------
--   DATA FOR TABLE T1
--   FILTER = none used
---------------------------------------------------
REM INSERTING into T1
Insert into T1 (ID) values (1);
Insert into T1 (ID) values (2);
Insert into T1 (ID) values (3);
Insert into T1 (ID) values (4);
Insert into T1 (ID) values (5);
Insert into T1 (ID) values (6);
Insert into T1 (ID) values (7);
Insert into T1 (ID) values (8);
Insert into T1 (ID) values (9);
Insert into T1 (ID) values (10);

---------------------------------------------------
--   END DATA FOR TABLE T1
---------------------------------------------------
--------------------------------------------------------
--  Constraints for Table T1
--------------------------------------------------------

<span style="color: #008000;">  </span><span style="color: #ff0000;"><span style="color: #008000;">ALTER TABLE "T1" ADD CONSTRAINT "T1_ID_PK" PRIMARY KEY ("ID") ENABLE;</span>
</span>--------------------------------------------------------
--  DDL for Index T1_ID_PK
--------------------------------------------------------

  <span style="color: #ff0000;">CREATE UNIQUE INDEX "T1_ID_PK" ON "T1" ("ID")
  ;
</span></pre>
<p>The DDL is not error free, to illustrate the issue, I selected only table T1 to export from my schema. If you run the sample script above as-is, you will receive an error “<em>ORA-00955: name is already used by an existing object</em>”.  It is because, the database wizard (<em>SQL Developer Version 2.1.0.63, Build MAIN-63.73</em>) , simply produces one section of DDL statements for constraints and another set for indexes within the script file.</p>
<pre>SQL&gt; --------------------------------------------------------
SQL&gt; --  DDL for Index T1_ID_PK
SQL&gt; --------------------------------------------------------
SQL&gt;
SQL&gt;   CREATE UNIQUE INDEX "T1_ID_PK" ON "T1" ("ID")
  2    ;
  CREATE UNIQUE INDEX "T1_ID_PK" ON "T1" ("ID")
                      *
ERROR at line 1:
<span style="color: #ff0000;">ORA-00955: name is already used by an existing object</span></pre>
<p>You will have to do a clean-up to make the script error free.</p>
<div id="crp_related"><strong>Related Posts:</strong><ul><li><a href="http://perumal.org/removing-oracle-10g-software-from-linux-server/" rel="bookmark" class="crp_title">Removing Oracle 10g Software from Linux Server</a></li><li><a href="http://perumal.org/oracle-statistics-package-statspack-a-free-performance-analysis-tool/" rel="bookmark" class="crp_title">Oracle Statistics Package (STATSPACK): A Free Performance Analysis Tool</a></li><li><a href="http://perumal.org/data-quality-the-accuracy-dimension/" rel="bookmark" class="crp_title">Data Quality: The Accuracy Dimension</a></li><li><a href="http://perumal.org/oracles-os-watcher-osw-utility/" rel="bookmark" class="crp_title">Oracle&#8217;s OS Watcher (OSW) Utility</a></li><li><a href="http://perumal.org/orion-oracle-io-numbers-calibration-tool-in-oracle-11g-r2/" rel="bookmark" class="crp_title">ORION: Oracle I/O Numbers Calibration Tool in Oracle 11g R2</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://perumal.org/sql-developer-database-export-wizard-to-export-ddl-and-data-as-dml/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Removing table rows using an inline view</title>
		<link>http://perumal.org/removing-table-rows-using-an-inline-view/</link>
		<comments>http://perumal.org/removing-table-rows-using-an-inline-view/#comments</comments>
		<pubDate>Fri, 26 Feb 2010 12:30:26 +0000</pubDate>
		<dc:creator>Ramasundaram Perumal</dc:creator>
				<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Oracle10g]]></category>
		<category><![CDATA[Oracle11g]]></category>
		<category><![CDATA[Oracle8i]]></category>
		<category><![CDATA[Oracle9i]]></category>
		<category><![CDATA[SQL & PL/SQL]]></category>
		<category><![CDATA[Tips & Techniques]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Techniques]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://perumal.org/?p=468</guid>
		<description><![CDATA[The SQL standard allows you to use an inline view in a DELETE statement, see the pseudo form below &#8211; If a condition such as key-preserved table is not met then it will result in error, “ORA-01752: cannot delete from view without exactly one key-preserved table.”
DELETE (SELECT some_column FROM table_one JOIN table_two USING (join_column));
I would [...]]]></description>
			<content:encoded><![CDATA[<p>The SQL standard allows you to use an inline view in a DELETE statement, see the pseudo form below &#8211; If a condition such as key-preserved table is not met then it will result in error, “<em>ORA-01752: cannot delete from view without exactly one key-preserved table.</em>”</p>
<pre>DELETE (SELECT some_column FROM table_one JOIN table_two USING (join_column));</pre>
<p>I would like to show you the caveat of using a DELETE statement with an inline view.  At the outset, one would think that the the removal of row is always perfomed on <em>table_one</em>, but it can be from <em>table_one</em> or <em>table_two</em>, it all depends on the physics of the table.  Let us start building a simple test case to illustrate the issue.</p>
<ul>
<li>Create two test tables, t1 and t2 with primary key</li>
</ul>
<pre>SQL&gt; SELECT banner FROM v$version
  2  WHERE rownum = 1;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi                

SQL&gt; SET HEAD OFF
SQL&gt; CREATE TABLE t1 (id NUMBER);

Table created.

SQL&gt; CREATE TABLE t2 (id NUMBER);

Table created.

SQL&gt; ALTER TABLE t1 ADD CONSTRAINT t1_id_pk PRIMARY KEY (id);

Table altered.

SQL&gt; ALTER TABLE t2 ADD CONSTRAINT t2_id_pk PRIMARY KEY (id);

Table altered.</pre>
<ul>
<li>Explain plan of DELETE statement with two different FROM clause (i.e  one from t1 to t2 and another from t2 to t1).</li>
</ul>
<pre>SQL&gt; EXPLAIN PLAN FOR DELETE (SELECT id FROM t1 JOIN t2 USING (id));

Explained.

SQL&gt; SELECT * FROM table(dbms_xplan.display(NULL,NULL,'BASIC'));

Plan hash value: 4198931308                                                     

----------------------------------------
| Id  | Operation           | Name     |
----------------------------------------
|   0 | DELETE STATEMENT    |          |
|   1 |  DELETE             | T1       |
|   2 |   NESTED LOOPS      |          |
|   3 |    TABLE ACCESS FULL| T2       |
|   4 |    INDEX UNIQUE SCAN| T1_ID_PK |
----------------------------------------                                        

11 rows selected.

SQL&gt; EXPLAIN PLAN FOR DELETE (SELECT id FROM t2 JOIN t1 USING (id));

Explained.

SQL&gt; SELECT * FROM table(dbms_xplan.display(NULL,NULL,'BASIC'));

Plan hash value: 988330285                                                      

----------------------------------------
| Id  | Operation           | Name     |
----------------------------------------
|   0 | DELETE STATEMENT    |          |
|   1 |  DELETE             | T2       |
|   2 |   NESTED LOOPS      |          |
|   3 |    TABLE ACCESS FULL| T1       |
|   4 |    INDEX UNIQUE SCAN| T2_ID_PK |
----------------------------------------                                        

11 rows selected.</pre>
<p>If you examine the execution plans above,  you see that the delete is performed on the table, which first appears in the FROM clause.  Also, If you force the optimizer to not use both the indexes, it will result in same behaviour.</p>
<pre>SQL&gt; EXPLAIN PLAN FOR DELETE
  2  	(SELECT /*+ NO_INDEX (t1 t1_id_pk)  NO_INDEX (t2 t2_id_pk)*/ id
  3  	   FROM t1 JOIN t2 USING (id));

Explained.

SQL&gt; SELECT * FROM table(dbms_xplan.display(NULL,NULL,'BASIC'));

Plan hash value: 3682150560                                                     

------------------------------------
| Id  | Operation           | Name |
------------------------------------
|   0 | DELETE STATEMENT    |      |
|   1 |  DELETE             | T1   |
|   2 |   HASH JOIN         |      |
|   3 |    TABLE ACCESS FULL| T2   |
|   4 |    TABLE ACCESS FULL| T1   |
------------------------------------                                            

11 rows selected.

SQL&gt; EXPLAIN PLAN FOR DELETE
  2  	(SELECT /*+ NO_INDEX (t1 t1_id_pk)  NO_INDEX (t2 t2_id_pk)*/ id
  3  	   FROM t2 JOIN t1 USING (id));

Explained.

SQL&gt; SELECT * FROM table(dbms_xplan.display(NULL,NULL,'BASIC'));

Plan hash value: 4238075461                                                     

------------------------------------
| Id  | Operation           | Name |
------------------------------------
|   0 | DELETE STATEMENT    |      |
|   1 |  DELETE             | T2   |
|   2 |   HASH JOIN         |      |
|   3 |    TABLE ACCESS FULL| T1   |
|   4 |    TABLE ACCESS FULL| T2   |
------------------------------------                                            

11 rows selected.</pre>
<ul>
<li>Remove T1’s primary key constraint/index and retain T2’s and obtain explain plans</li>
</ul>
<pre>SQL&gt; ALTER TABLE t1 DROP CONSTRAINT t1_id_pk;

Table altered.

SQL&gt; EXPLAIN PLAN FOR DELETE (SELECT id FROM t1 JOIN t2 USING (id));

Explained.

SQL&gt; SELECT * FROM table(dbms_xplan.display(NULL,NULL,'BASIC'));

Plan hash value: 2997925617                                                     

----------------------------------------
| Id  | Operation           | Name     |
----------------------------------------
|   0 | DELETE STATEMENT    |          |
|   1 |  DELETE             | T1       |
|   2 |   NESTED LOOPS      |          |
|   3 |    TABLE ACCESS FULL| T1       |
|   4 |    INDEX UNIQUE SCAN| T2_ID_PK |
----------------------------------------                                        

11 rows selected.

SQL&gt; EXPLAIN PLAN FOR DELETE (SELECT id FROM t2 JOIN t1 USING (id));

Explained.

SQL&gt; SELECT * FROM table(dbms_xplan.display(NULL,NULL,'BASIC'));

Plan hash value: 2997925617                                                     

----------------------------------------
| Id  | Operation           | Name     |
----------------------------------------
|   0 | DELETE STATEMENT    |          |
|   1 |  DELETE             | T1       |
|   2 |   NESTED LOOPS      |          |
|   3 |    TABLE ACCESS FULL| T1       |
|   4 |    INDEX UNIQUE SCAN| T2_ID_PK |
----------------------------------------                                        

11 rows selected.</pre>
<p>After droping the primary constraint/index on T1, the DELETE is performed on T1 no matter whether your FROM clause is T1 to T2,  T2 to T1.</p>
<ul>
<li>Remove T2’s primary key constraint/index and add primary key constraint/index to T1 and obtain explain plans</li>
</ul>
<pre>SQL&gt; ALTER TABLE t2 DROP CONSTRAINT t2_id_pk;

Table altered.

SQL&gt; ALTER TABLE t1 ADD CONSTRAINT t1_id_pk PRIMARY KEY (id);

Table altered.

SQL&gt; EXPLAIN PLAN FOR DELETE (SELECT id FROM t1 JOIN t2 USING (id));

Explained.

SQL&gt; SELECT * FROM table(dbms_xplan.display(NULL,NULL,'BASIC'));

Plan hash value: 4135363241                                                     

----------------------------------------
| Id  | Operation           | Name     |
----------------------------------------
|   0 | DELETE STATEMENT    |          |
|   1 |  DELETE             | T2       |
|   2 |   NESTED LOOPS      |          |
|   3 |    TABLE ACCESS FULL| T2       |
|   4 |    INDEX UNIQUE SCAN| T1_ID_PK |
----------------------------------------                                        

11 rows selected.

SQL&gt; EXPLAIN PLAN FOR DELETE (SELECT id FROM t2 JOIN t1 USING (id));

Explained.

SQL&gt; SELECT * FROM table(dbms_xplan.display(NULL,NULL,'BASIC'));

Plan hash value: 4135363241                                                     

----------------------------------------
| Id  | Operation           | Name     |
----------------------------------------
|   0 | DELETE STATEMENT    |          |
|   1 |  DELETE             | T2       |
|   2 |   NESTED LOOPS      |          |
|   3 |    TABLE ACCESS FULL| T2       |
|   4 |    INDEX UNIQUE SCAN| T1_ID_PK |
----------------------------------------                                        

11 rows selected.</pre>
<p>After droping the primary constraint/index on T2 and recreating the primary key primary constraint/index on T1, the DELETE is performed on T2 no matter whether your FROM clause is T1 to T2,  T2 to T1.</p>
<p>If you run the DELETE statement when there is no index on both the tables,  it will result in error &#8220;“<em>ORA-01752: cannot delete from view without exactly one key-preserved table.</em>” </p>
<pre>SQL&gt; ALTER TABLE t1 DROP CONSTRAINT t1_id_pk;

Table altered.

SQL&gt; EXPLAIN PLAN FOR DELETE (SELECT id FROM t2 JOIN t1 USING (id));
EXPLAIN PLAN FOR DELETE (SELECT id FROM t2 JOIN t1 USING (id))
                        *
ERROR at line 1:
ORA-01752: cannot delete from view without exactly one key-preserved table</pre>
<p>Don&#8217;t get excited with the new features or syntaxes, test things thoroughly and cover all possible scenarios before you put in production.</p>
<div id="crp_related"><strong>Related Posts:</strong><ul><li><a href="http://perumal.org/oracle-metadata-plan_table/" rel="bookmark" class="crp_title">Oracle Metadata: PLAN_TABLE</a></li><li><a href="http://perumal.org/oracle-install-guides/" rel="bookmark" class="crp_title">Oracle Install Guides</a></li><li><a href="http://perumal.org/dbms_xplandisplay_cursor-results-in-error-cannot-fetch-plan-for-sql_id-9babjv8yq8ru3-child_number-0/" rel="bookmark" class="crp_title">DBMS_XPLAN.DISPLAY_CURSOR results in error cannot fetch plan for SQL_ID: 9babjv8yq8ru3, CHILD_NUMBER: 0</a></li><li><a href="http://perumal.org/removing-oracle-10g-software-from-linux-server/" rel="bookmark" class="crp_title">Removing Oracle 10g Software from Linux Server</a></li><li><a href="http://perumal.org/how-to-read-an-oracle-sql-execution-plan/" rel="bookmark" class="crp_title">How to read an Oracle SQL Execution Plan?</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://perumal.org/removing-table-rows-using-an-inline-view/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Software Performance and Scalability: A Quantitative Approach</title>
		<link>http://perumal.org/software-performance-and-scalability-a-quantitative-approach/</link>
		<comments>http://perumal.org/software-performance-and-scalability-a-quantitative-approach/#comments</comments>
		<pubDate>Thu, 11 Feb 2010 13:00:39 +0000</pubDate>
		<dc:creator>Ramasundaram Perumal</dc:creator>
				<category><![CDATA[Book Review]]></category>

		<guid isPermaLink="false">http://perumal.org/?p=461</guid>
		<description><![CDATA[Software Performance and Scalability: A Quantitative Approach (Wiley, May 2009) is for people involved in designing, developing, testing, implementing and managing enterprise applications. This book provides the necessary quantitative foundation, analytical and measurement aspects of performance and scalability -  effective blend of studies and practical examples, which makes it thorough, it easier to read and informative.
Author [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.amazon.com/Software-Performance-Scalability-Quantitative-Engineering/dp/0470462531/ref=cm_cr_pr_product_top"><img class="alignleft size-full wp-image-467" title="Software Performance and Scalability" src="http://perumal.org/wp-content/uploads/2010/02/SoftwarePerformanceandScalabilityBook.jpg" alt="" width="100" height="160" />Software Performance and Scalability: A Quantitative Approach (Wiley, May 2009)</a> is for people involved in designing, developing, testing, implementing and managing enterprise applications. This book provides the necessary quantitative foundation, analytical and measurement aspects of performance and scalability -  effective blend of studies and practical examples, which makes it thorough, it easier to read and informative.</p>
<p>Author has divided this book into three parts:  <em>Part 1: The Basics </em> - This part lays the foundation for understanding the factors that affect the performance and scalability of a software product in general. <em>Part 2: Applying Queuing Theory</em> &#8211; Queuing theory is the mathematical study of waiting lines or queues for a system that depends on limited resources to complete certain tasks. <em>Part 3: Applying API Profiling</em> &#8211; API profiling provides quantitative information about how a software program is executed internally at the API level. Such information is useful in identifying the most expensive execution paths from performance and scalability perspectives.</p>
<p>You can take advantage of <a href="http://books.google.com/books?id=D5fcbZdCUCUC&amp;printsec=frontcover&amp;dq=Software+Performance+and+Scalability&amp;cd=1#v=onepage&amp;q=&amp;f=false">Google Books</a> for the detailed preview of the content. Alternatively, you can also visit the <a href="http://www.perfmath.com/home.html">book’s website</a> for updated information.</p>
<p>As you read, you will realize that virtualization environment and its effects on scalability and performance is not covered in this book.  Hope to see this in the future editions.  It is a must read for anyone who is serious about building enterprise level products or applications. I hope you&#8217;ll enjoy this book as much as I have had and it is a happy addition to my library.</p>
<div id="crp_related"><strong>Related Posts:</strong><ul><li><a href="http://perumal.org/removing-oracle-10g-software-from-linux-server/" rel="bookmark" class="crp_title">Removing Oracle 10g Software from Linux Server</a></li><li><a href="http://perumal.org/oracle-metadata-plan_table/" rel="bookmark" class="crp_title">Oracle Metadata: PLAN_TABLE</a></li><li><a href="http://perumal.org/orion-oracle-io-numbers-calibration-tool-in-oracle-11g-r2/" rel="bookmark" class="crp_title">ORION: Oracle I/O Numbers Calibration Tool in Oracle 11g R2</a></li><li><a href="http://perumal.org/oracle-install-guides/" rel="bookmark" class="crp_title">Oracle Install Guides</a></li><li><a href="http://perumal.org/data-quality-the-accuracy-dimension/" rel="bookmark" class="crp_title">Data Quality: The Accuracy Dimension</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://perumal.org/software-performance-and-scalability-a-quantitative-approach/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Joins, Join Conditions, Filters and Join Types</title>
		<link>http://perumal.org/joins-join-conditions-filters-and-join-types/</link>
		<comments>http://perumal.org/joins-join-conditions-filters-and-join-types/#comments</comments>
		<pubDate>Thu, 11 Feb 2010 08:28:03 +0000</pubDate>
		<dc:creator>Ramasundaram Perumal</dc:creator>
				<category><![CDATA[Foundations]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Oracle10g]]></category>
		<category><![CDATA[Oracle11g]]></category>
		<category><![CDATA[Oracle9i]]></category>
		<category><![CDATA[SQL & PL/SQL]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://perumal.org/?p=459</guid>
		<description><![CDATA[Joins
A join is a query that combines rows from two or more tables. Oracle performs a join whenever multiple tables appear in the FROM clause of the query.  Below is a SQL join statement, legacy syntax and ANSI/ISO syntax (also referred as new join syntax, was first introduced in Oracle 9i release) in a simple [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Joins</strong></p>
<p>A join is a query that combines rows from two or more tables. Oracle performs a join whenever multiple tables appear in the FROM clause of the query.  Below is a SQL join statement, legacy syntax and ANSI/ISO syntax (also referred as new join syntax, was first introduced in Oracle 9i release) in a simple pseudo code form.</p>
<ul>
<li><em>ANSI/ISO Syntax:</em></li>
</ul>
<pre>SELECT * FROM &lt;table one&gt; [join type] JOIN &lt;table two&gt;
USING &lt;join columns&gt; | ON &lt;join conditions&gt;
[WHERE &lt;where clause filters/restrictions&gt;]</pre>
<ul>
<li><em>Legacy Syntax:</em></li>
</ul>
<pre>SELECT * FROM &lt;table one&gt;, &lt;table two&gt;
[WHERE &lt;where clause join conditions&gt;]
[&lt;where clause filters/restrictions&gt;]</pre>
<p><strong>Join Conditions</strong></p>
<p>Most of the queries will contain at least one join condition, either in the FROM clause or in the WHERE clause. The join condition compares two columns, each from a different table. To execute a join, Oracle database combines pairs of rows, each containing one row from each table, for which the join condition evaluates to TRUE.</p>
<p>To execute a join of three or more tables, Oracle first joins two of the tables based on the join conditions comparing their columns and then joins the result to another table based on join conditions containing columns of the joined tables and the new table. Oracle continues this process until all tables are joined into the result. The optimizer determines the order in which Oracle joins tables based on the join conditions, indexes on the tables, and, any available statistics for the tables.</p>
<p><strong>Filters (also known as Restrictions)</strong></p>
<p>A WHERE clause can also contain filter conditions that refer to columns of only one table, which can further restrict the rows returned by the join query.</p>
<ul>
<li>Let us create some test tables to demonstrate different type of joins</li>
</ul>
<pre>SQL&gt; CREATE TABLE t1
  2  AS
  3  SELECT * FROM
  4  (
  5  SELECT rownum-1 id,
  6  DECODE(rownum-1,0,'Zero',NULL) word,
  7  (rownum-1)*10 t1n,
  8  SUBSTR(DECODE(rownum-1,0,'Zero',TO_CHAR(TO_DATE((rownum-1)*10,'J'),'Jsp')),1,12) t1word,
  9  (rownum-1)*1000 t1value
 10  FROM dual CONNECT BY LEVEL &lt;= 11
 11  )
 12  WHERE ID IN (0,1,3,5,7,10); 

Table created.

SQL&gt; CREATE TABLE t2
  2  AS
  3  SELECT * FROM
  4  (
  5  SELECT rownum-1 id,
  6  DECODE(rownum-1,0,'Zero',NULL) word,
  7  (rownum-1)*100 t2n,
  8  SUBSTR(DECODE(rownum-1,0,'Zero',TO_CHAR(TO_DATE((rownum-1)*100,'J'),'Jsp')),1,12) t2word,
  9  (rownum-1)*1000 t2value
 10  FROM DUAL CONNECT BY LEVEL &lt;= 11
 11  )
 12  WHERE ID IN (0,1,2,4,6,8,9); 

Table created. 

SQL&gt; CREATE TABLE t3
  2  AS
  3  SELECT 'GRP' || LPAD (ROWNUM, 2, '0') group_id,
  4         ((ROWNUM - 1) * 2000) + 1 low_value, ROWNUM * 2000 high_value
  5  FROM DUAL CONNECT BY LEVEL &lt;= 6;

Table created.

SQL&gt; SELECT * FROM t1;

        ID WORD        T1N T1WORD          T1VALUE
---------- ---- ---------- ------------ ----------
         0 Zero          0 Zero                  0
         1              10 Ten                1000
         3              30 Thirty             3000
         5              50 Fifty              5000
         7              70 Seventy            7000
        10             100 One Hundred       10000

6 rows selected.

SQL&gt; SELECT * FROM t2;

        ID WORD        T2N T2WORD          T2VALUE
---------- ---- ---------- ------------ ----------
         0 Zero          0 Zero                  0
         1             100 One Hundred        1000
         2             200 Two Hundred        2000
         4             400 Four Hundred       4000
         6             600 Six Hundred        6000
         8             800 Eight Hundre       8000
         9             900 Nine Hundred       9000

7 rows selected.

SQL&gt; SELECT * FROM t3;

GROUP  LOW_VALUE HIGH_VALUE
----- ---------- ----------
GRP01          1       2000
GRP02       2001       4000
GRP03       4001       6000
GRP04       6001       8000
GRP05       8001      10000
GRP06      10001      12000

6 rows selected.</pre>
<p><strong>Join Types</strong></p>
<ul>
<li><strong><em>Cross Joins:</em></strong> If two tables in a join query have no join condition, then Oracle Database returns their Cartesian product. Oracle combines each row of one table with each row of the other. </li>
</ul>
<p style="padding-left: 30px;"><span style="text-decoration: underline;">ANSI/ISO Syntax</span></p>
<pre style="padding-left: 30px;">SQL&gt; SELECT t1n, t2word, t2n, t2word
  2  FROM t1 CROSS JOIN t2;

       T1N T2WORD              T2N T2WORD
---------- ------------ ---------- ------------
         0 Zero                  0 Zero
...
       100 Nine Hundred        900 Nine Hundred

42 rows selected.</pre>
<p style="padding-left: 30px;"><span style="text-decoration: underline;">Legacy Syntax</span></p>
<pre style="padding-left: 30px;">SQL&gt; SELECT t1n, t2word, t2n, t2word
  2  FROM t1, t2;

       T1N T2WORD              T2N T2WORD
---------- ------------ ---------- ------------
         0 Zero                  0 Zero
...
        100 Nine Hundred        900 Nine Hundred

42 rows selected.</pre>
<ul>
<li><strong><em>Equi Joins (also known as Natural Joins):</em></strong> An equijoin is a join with a join condition containing an equality operator. An equijoin combines rows that have equivalent values for the specified columns.</li>
</ul>
<p style="padding-left: 60px;"><em>// Using Clause //</em></p>
<p style="padding-left: 60px;"> <span style="text-decoration: underline;">ANSI/ISO Syntax</span></p>
<pre style="padding-left: 60px;">SQL&gt; SELECT id, t1.word, t2.word,t1n, t1word, t2n, t2word
  2  FROM t1 JOIN t2 USING(id);

        ID WORD WORD        T1N T1WORD              T2N T2WORD
---------- ---- ---- ---------- ------------ ---------- ------------
         0 Zero Zero          0 Zero                  0 Zero
         1                   10 Ten                 100 One Hundred</pre>
<p style="padding-left: 60px;"><span style="text-decoration: underline;">Legacy Syntax</span></p>
<pre style="padding-left: 60px;">SQL&gt; SELECT t1.id, t1.word, t2.word,t1n, t1word, t2n, t2word
  2  FROM t1, t2
  3  WHERE t1.id = t2.id;

        ID WORD WORD        T1N T1WORD              T2N T2WORD
---------- ---- ---- ---------- ------------ ---------- ------------
         0 Zero Zero          0 Zero                  0 Zero
         1                   10 Ten                 100 One Hundred</pre>
<p style="padding-left: 60px;"><em>// Natural Join Clause &#8211; performs a join on all columns with the matching names in T1 and T2//</em></p>
<p style="padding-left: 60px;"><span style="text-decoration: underline;">ANSI/ISO Syntax</span></p>
<pre style="padding-left: 60px;">SQL&gt; SELECT id, word, t1n, t1word, t2n, t2word
  2  FROM t1 NATURAL JOIN t2;

        ID WORD        T1N T1WORD              T2N T2WORD
---------- ---- ---------- ------------ ---------- ------------
         0 Zero          0 Zero                  0 Zero</pre>
<p style="padding-left: 60px;"><span style="text-decoration: underline;">Legacy Syntax</span></p>
<pre style="padding-left: 60px;">SQL&gt; SELECT t1.id, t2.word, t1n, t1word, t2n, t2word
  2  FROM t1, t2
  3  WHERE t1.id = t2.id
  4    AND t1.word = t2.word;

        ID WORD        T1N T1WORD              T2N T2WORD
---------- ---- ---------- ------------ ---------- ------------
         0 Zero          0 Zero                  0 Zero</pre>
<p style="padding-left: 60px;"><em>// ON Clause //</em></p>
<p style="padding-left: 60px;"><span style="text-decoration: underline;">ANSI/ISO Syntax</span></p>
<pre style="padding-left: 60px;">SQL&gt; SELECT t1.id, t1.word, t1n, t1word, t2n, t2word
  2  FROM t1 JOIN t2 ON (t1.t1n = t2.t2n);

        ID WORD        T1N T1WORD              T2N T2WORD
---------- ---- ---------- ------------ ---------- ------------
         0 Zero          0 Zero                  0 Zero
        10             100 One Hundred         100 One Hundred</pre>
<p style="padding-left: 60px;"><span style="text-decoration: underline;">Legacy Syntax</span></p>
<pre style="padding-left: 60px;">SQL&gt; SELECT t1.id, t1.word, t1n, t1word, t2n, t2word
  2  FROM t1, t2
  3  WHERE t1.t1n = t2.t2n;

        ID WORD        T1N T1WORD              T2N T2WORD
---------- ---- ---------- ------------ ---------- ------------
         0 Zero          0 Zero                  0 Zero
        10             100 One Hundred         100 One Hundred</pre>
<ul>
<li><strong><em>Theta Joins (also known as Inner Joins):</em></strong> Theta join is technically, nothing but a cross join with a join condition. Simply put, instead of returning all the rows of a cartesian product, only rows matching the join condition are returned.</li>
</ul>
<p style="padding-left: 30px;"><span style="text-decoration: underline;">ANSI/ISO Syntax</span></p>
<pre style="padding-left: 30px;">SQL&gt; -- Without Inner Keyword
SQL&gt; SELECT t1.id,t1.word,t1.t1value,t3.group_id
  2  FROM t1 JOIN t3 ON t1.t1value
  3  BETWEEN t3.low_value AND t3.high_value;

        ID WORD    T1VALUE GROUP
---------- ---- ---------- -----
        10           10000 GRP05
         7            7000 GRP04
         5            5000 GRP03
         3            3000 GRP02
         1            1000 GRP01

SQL&gt; -- With Inner Keyword
SQL&gt; SELECT t1.id,t1.word,t1.t1value,t3.group_id
  2  FROM t1 INNER JOIN t3 ON t1.t1value
  3  BETWEEN t3.low_value AND t3.high_value;

        ID WORD    T1VALUE GROUP
---------- ---- ---------- -----
        10           10000 GRP05
         7            7000 GRP04
         5            5000 GRP03
         3            3000 GRP02
         1            1000 GRP01</pre>
<p style="padding-left: 30px;"><span style="text-decoration: underline;">Legacy Syntax</span></p>
<pre style="padding-left: 30px;">SQL&gt; SELECT t1.id,t1.word,t1.t1value,t3.group_id
  2  FROM t1, t3
  3  WHERE t1.t1value
  4  BETWEEN t3.low_value AND t3.high_value;

        ID WORD    T1VALUE GROUP
---------- ---- ---------- -----
        10           10000 GRP05
         7            7000 GRP04
         5            5000 GRP03
         3            3000 GRP02
         1            1000 GRP01</pre>
<ul>
<li><strong><em>Outer Joins:</em></strong> An outer join extends the result of a simple join. An outer join returns all rows that satisfy the join condition and also returns some or all of those rows from one table for which no rows from the other satisfy the join condition.</li>
</ul>
<p style="padding-left: 30px;">// To write a query that performs an outer join of tables T1 and T2 and returns all rows from T1 (a left outer join)</p>
<p style="padding-left: 60px;"><span style="text-decoration: underline;">ANSI/ISO Syntax</span> (<em>Use the LEFT [OUTER] JOIN syntax in the FROM clause</em>)</p>
<pre style="padding-left: 60px;">SQL&gt; SELECT t1.id, t2.word, t2.id, t2.word
  2  FROM t1 LEFT OUTER JOIN t2 ON (t1.id = t2.id);

        ID WORD         ID WORD
---------- ---- ---------- ----
         0 Zero          0 Zero
         1               1
         7
         5
         3
        10

6 rows selected.</pre>
<p style="padding-left: 60px;"><span style="text-decoration: underline;">Legacy Syntax </span>(<em>Apply the outer join operator (+) to all columns of T2 in the join condition in the WHERE clause</em>)</p>
<pre style="padding-left: 60px;">SQL&gt; SELECT t1.id, t2.word, t2.id, t2.word
  2  FROM t1, t2
  3  WHERE t1.id = t2.id(+);

        ID WORD         ID WORD
---------- ---- ---------- ----
         0 Zero          0 Zero
         1               1
         7
         5
         3
        10

6 rows selected.</pre>
<p style="padding-left: 30px;">// To write a query that performs an outer join of tables T1 and T2 and returns all rows from T2 (a right outer join)</p>
<p style="padding-left: 60px;"><span style="text-decoration: underline;">ANSI/ISO Syntax</span> (<em>Use the RIGHT [OUTER] JOIN syntax in the FROM clause</em>)</p>
<pre style="padding-left: 60px;">SQL&gt; SELECT t1.id, t2.word, t2.id, t2.word
  2  FROM t1 RIGHT OUTER JOIN t2 ON (t1.id = t2.id);

        ID WORD         ID WORD
---------- ---- ---------- ----
         0 Zero          0 Zero
         1               1
                         8
                         2
                         6
                         4
                         9

7 rows selected.</pre>
<p style="padding-left: 60px;"><span style="text-decoration: underline;">Legacy Syntax </span>(<em>Apply the outer join operator (+) to all columns of T1 in the join condition in the WHERE clause</em>)</p>
<pre style="padding-left: 60px;">SQL&gt; SELECT t1.id, t2.word, t2.id, t2.word
  2  FROM t1, t2
  3  WHERE t1.id (+)= t2.id;

        ID WORD         ID WORD
---------- ---- ---------- ----
         0 Zero          0 Zero
         1               1
                         8
                         2
                         6
                         4
                         9

7 rows selected.</pre>
<p style="padding-left: 30px;">// To write a query that performs an outer join and returns all rows from T1  and T2, extended with nulls if they do not satisfy the join condition (a full outer join), use the FULL [OUTER] JOIN syntax in the FROM clause.</p>
<p style="padding-left: 60px;"><span style="text-decoration: underline;">ANSI/ISO Syntax</span></p>
<pre style="padding-left: 60px;">SQL&gt; SELECT t1.id, t2.word, t2.id, t2.word
  2  FROM t1 FULL OUTER JOIN t2 ON (t1.id = t2.id);

        ID WORD         ID WORD
---------- ---- ---------- ----
         0 Zero          0 Zero
         1               1
         7
         5
         3
        10
                         8
                         2
                         6
                         4
                         9

11 rows selected.</pre>
<p style="padding-left: 60px;"><span style="text-decoration: underline;">Legacy Syntax </span>(<em>Not available</em>)</p>
<ul>
<li><strong><em>Self Joins:</em></strong> A self join is a join of a table to itself. This table appears twice in the FROM clause and is followed by table aliases that qualify column names in the join condition. To perform a self join, Oracle Database combines and returns rows of the table that satisfy the join condition.</li>
</ul>
<p style="padding-left: 30px;"><span style="text-decoration: underline;">ANSI/ISO Syntax</span></p>
<pre style="padding-left: 30px;">SQL&gt; SELECT a.id, a.word, a.t1n, b.id, b.word, b.t1n
  2  FROM t1 a JOIN t1 b ON (a.id = b.t1n);

        ID WORD        T1N         ID WORD        T1N
---------- ---- ---------- ---------- ---- ----------
         0 Zero          0          0 Zero          0
        10             100          1              10</pre>
<p style="padding-left: 30px;"><span style="text-decoration: underline;">Legacy Syntax</span></p>
<pre style="padding-left: 30px;">SQL&gt; SELECT a.id, a.word, a.t1n, b.id, b.word, b.t1n
  2  FROM t1 a, t1 b
  3  WHERE a.id = b.t1n;

        ID WORD        T1N         ID WORD        T1N
---------- ---- ---------- ---------- ---- ----------
         0 Zero          0          0 Zero          0
        10             100          1              10</pre>
<ul>
<li><strong><em>Anti-Joins:</em></strong> An antijoin returns rows from the left side of the predicate for which there are no (NOT IN or NOT EXISTS) corresponding rows on the right side of the predicate. Simply put, where rows from one table with no matching rows from other table are returned.</li>
</ul>
<pre style="padding-left: 30px;">SQL&gt; SELECT id, t1n, t1word
  2  FROM t1
  3  WHERE id NOT IN (SELECT id FROM t2);

        ID        T1N T1WORD
---------- ---------- ------------
         3         30 Thirty
         5         50 Fifty
         7         70 Seventy
        10        100 One Hundred

SQL&gt; SELECT id, t1n, t1word
  2  FROM t1
  3  WHERE NOT EXISTS
  4  	   (SELECT id FROM t2 WHERE t2.id = t1.id);

        ID        T1N T1WORD
---------- ---------- ------------
         7         70 Seventy
         5         50 Fifty
         3         30 Thirty
        10        100 One Hundred</pre>
<ul>
<li><strong><em>Semi-Joins:</em></strong> A semijoin returns rows that match an IN or EXISTS subquery without duplicating rows from the left side of the predicate when multiple rows on the right side satisfy the criteria of the subquery. Simply put, all rows from table on the left are returned for a matching condition on the right.</li>
</ul>
<pre style="padding-left: 30px;">SQL&gt; SELECT id, t1n, t1word
  2  FROM t1
  3  WHERE id IN (SELECT id FROM t2);

        ID        T1N T1WORD
---------- ---------- ------------
         0          0 Zero
         1         10 Ten

SQL&gt; SELECT id, t1n, t1word
  2  FROM t1
  3  WHERE EXISTS
  4  	   (SELECT id FROM t2 WHERE t2.id = t1.id);

        ID        T1N T1WORD
---------- ---------- ------------
         0          0 Zero
         1         10 Ten</pre>
<div id="crp_related"><strong>Related Posts:</strong><ul><li><a href="http://perumal.org/removing-table-rows-using-an-inline-view/" rel="bookmark" class="crp_title">Removing table rows using an inline view</a></li><li><a href="http://perumal.org/sql-developer-database-export-wizard-to-export-ddl-and-data-as-dml/" rel="bookmark" class="crp_title">SQL Developer: Database Export Wizard to export DDL and Data as DML</a></li><li><a href="http://perumal.org/oracle-analytical-functions-look-back-and-look-ahead/" rel="bookmark" class="crp_title">Oracle Analytical Functions &#8211; Look Back and Look Ahead</a></li><li><a href="http://perumal.org/optimizer-index-access-paths-why-oracle-is-not-using-my-index/" rel="bookmark" class="crp_title">Optimizer Index Access Paths: Why Oracle is not using my Index?</a></li><li><a href="http://perumal.org/dbms_xplandisplay_cursor-does-not-display-execution-plan-of-all-children-associated-with-the-sql_id/" rel="bookmark" class="crp_title">DBMS_XPLAN.DISPLAY_CURSOR does not display execution plan of all children associated with the SQL_ID</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://perumal.org/joins-join-conditions-filters-and-join-types/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Data Quality: The Accuracy Dimension</title>
		<link>http://perumal.org/data-quality-the-accuracy-dimension/</link>
		<comments>http://perumal.org/data-quality-the-accuracy-dimension/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 17:06:58 +0000</pubDate>
		<dc:creator>Ramasundaram Perumal</dc:creator>
				<category><![CDATA[Book Review]]></category>

		<guid isPermaLink="false">http://perumal.org/?p=457</guid>
		<description><![CDATA[Data quality is an important element in data management; it is a larger topic by itself. If you are looking for a book on data quality, don’t look further. Get a copy of Data Quality: The Accuracy Dimension (Morgan Kaufmann; 1st Edition, 2003).
This book is about data accuracy, divided into three parts &#8211; Part 1 [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://perumal.org/wp-content/uploads/2010/02/DataQualityTheAccuracyDimension.jpeg"></a><a href="http://www.amazon.com/Data-Quality-Accuracy-Dimension-Management/dp/1558608915"><img class="alignleft size-full wp-image-458" title="DataQualityTheAccuracyDimension" src="http://perumal.org/wp-content/uploads/2010/02/DataQualityTheAccuracyDimension.jpeg" alt="" width="120" height="180" /></a>Data quality is an important element in data management; it is a larger topic by itself. If you are looking for a book on data quality, don’t look further. Get a copy of <a href="http://www.amazon.com/Data-Quality-Accuracy-Dimension-Management/dp/1558608915">Data Quality: The Accuracy Dimension (Morgan Kaufmann; 1st Edition, 2003)</a>.</p>
<p>This book is about data accuracy, divided into three parts &#8211; <em>Part 1 Understanding Data Accuracy</em>: defines inaccurate data, shows the scope of problems that exists in the real world, and covers how data becomes inaccurate. <em>Part 2 Implementing a Data Quality Assurance Program</em>: covers how data quality assurance program is constructed with the inside-out approach, and covers the methodology used, the skills needed, and the general business cases. <em>Part 3 Data Profiling Technology</em>: focuses on the technology of data profiling. It describes the basic concept of technology and shows how individual parts contribute to overall result.</p>
<p>The author has explained the concepts, techniques, and the framework required to analyze and improve usefulness of the source data. It is a must read, if you are a professional working in the field of data quality, data integration, data architecture, or data warehousing. Many books are out there in the market on the similar subject, but this one is easy to study and does provide a new ground in 300 pages.</p>
<p>You can preview this book at <a href="http://books.google.com/books?id=bcntKQzsnX0C&amp;printsec=frontcover">Google Books</a>.</p>
<p>Overall, this is a very good book. I wish I would have read it several years ago!</p>
<div id="crp_related"><strong>Related Posts:</strong><ul><li><a href="http://perumal.org/oracles-os-watcher-osw-utility/" rel="bookmark" class="crp_title">Oracle&#8217;s OS Watcher (OSW) Utility</a></li><li><a href="http://perumal.org/orion-oracle-io-numbers-calibration-tool-in-oracle-11g-r2/" rel="bookmark" class="crp_title">ORION: Oracle I/O Numbers Calibration Tool in Oracle 11g R2</a></li><li><a href="http://perumal.org/the-on-board-monitor-ltom-embedded-real-time-data-collection-and-diagnostics-platform/" rel="bookmark" class="crp_title">The On-Board Monitor (LTOM) &#8211; Embedded Real-Time Data Collection and Diagnostics Platform</a></li><li><a href="http://perumal.org/oracle-statistics-package-statspack-a-free-performance-analysis-tool/" rel="bookmark" class="crp_title">Oracle Statistics Package (STATSPACK): A Free Performance Analysis Tool</a></li><li><a href="http://perumal.org/sql-developer-database-export-wizard-to-export-ddl-and-data-as-dml/" rel="bookmark" class="crp_title">SQL Developer: Database Export Wizard to export DDL and Data as DML</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://perumal.org/data-quality-the-accuracy-dimension/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Virtual / NOSEGMENT / Fake Indexes</title>
		<link>http://perumal.org/virtual-nosegment-fake-indexes/</link>
		<comments>http://perumal.org/virtual-nosegment-fake-indexes/#comments</comments>
		<pubDate>Tue, 29 Dec 2009 22:23:09 +0000</pubDate>
		<dc:creator>Ramasundaram Perumal</dc:creator>
				<category><![CDATA[Indexes]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Tips & Techniques]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Techniques]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Tuning]]></category>

		<guid isPermaLink="false">http://perumal.org/?p=454</guid>
		<description><![CDATA[Virtual Indexes (aka NOSEGMENT Indexes or Fake Indexes) are useful to check whether the creation of an Index affects the execution plan with out having to create the actual index. Virtual index is just a definition without a physical index segment so it does not consume disk space. Additionally, virtual index is available to a [...]]]></description>
			<content:encoded><![CDATA[<p>Virtual Indexes (aka NOSEGMENT Indexes or Fake Indexes) are useful to check whether the creation of an Index affects the execution plan with out having to create the actual index. Virtual index is just a definition without a physical index segment so it does not consume disk space. Additionally, virtual index is available to a session only when a session explicitly issues an alter session command; hence it does not affect the normal processing of your system.</p>
<ul>
<li>Let’s create a test table and populate</li>
</ul>
<pre>SQL&gt; CREATE TABLE t (n CONSTRAINT t_pk PRIMARY KEY, d)
  2  AS
  3  SELECT rownum, mod(rownum,5)
  4  FROM dual CONNECT BY level &lt;= 10000;

Table created.</pre>
<ul>
<li>As expected, querying the table on primary key column resulted in index unique scan and on non-indexed column resulted in full table scan.</li>
</ul>
<pre>SQL&gt; SET AUTOTRACE TRACEONLY EXPLAIN
SQL&gt; SELECT * FROM t WHERE n = 5;

Execution Plan
----------------------------------------------------------
Plan hash value: 1303508680

------------------------------------------------------------------------------------
| Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |      |     1 |    26 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T    |     1 |    26 |     2   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | T_PK |     1 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("N"=5)

SQL&gt; SELECT * FROM t WHERE d = 0;

Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  2000 | 52000 |     6   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |  2000 | 52000 |     6   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("D"=0)

Note
-----
   - dynamic sampling used for this statement</pre>
<p>We can create a fake index by simply adding <span style="font-family: courier new,courier;">NOSEGMENT </span>clause to the <span style="font-family: courier new,courier;">CREATE INDEX </span>statement. The <span style="font-family: courier new,courier;">NOSEGMENT</span> clause specifies the index is virtual. By setting the hidden parameter <span style="font-family: courier new,courier;">_use_nosegment_indexes </span>to TRUE; you are instructing the optimizer to use the index, if it is useful.</p>
<pre>SQL&gt; CREATE INDEX t_d_virtual_idx ON t(d) NOSEGMENT;

Index created.

SQL&gt; ALTER SESSION SET "_use_nosegment_indexes" = TRUE;

Session altered.

SQL&gt; SELECT * FROM t WHERE d = 0;

Execution Plan
----------------------------------------------------------
Plan hash value: 3632700478

-----------------------------------------------------------------------------------------------
| Id  | Operation                   | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                 |  2000 | 52000 |     5   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T               |  2000 | 52000 |     5   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | T_D_VIRTUAL_IDX |    40 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("D"=0)

Note
-----
   - dynamic sampling used for this statement</pre>
<p>The optimizer determined that the virtual index deemed useful; hence, changed the execution plan from full table scan to index range scan. </p>
<p>Fake index is really useful, if you have a large table and would like to check if the new index will be used by the optimizer. Since there is no storage area associated with these indexes, they do not have any other overhead. Some important characteristics of  fake index are:</p>
<ul>
<li>Virtual indexes are reflected in USER_OBJECTS, DBA_OBJECTS but are not reflected in USER_INDEXES, DBA_INDEXES</li>
</ul>
<pre>SQL&gt; SET AUTOTRACE OFF
SQL&gt; SELECT index_name FROM user_indexes WHERE table_name = 'T';

INDEX_NAME
------------------------------
T_PK

SQL&gt; SELECT object_name FROM user_objects WHERE object_name LIKE 'T%' and object_type = 'INDEX'

OBJECT_NAME
------------------------------
T_D_VIRTUAL_IDX
T_PK</pre>
<ul>
<li>ALTER INDEX command on a fake index will result in ORA-08114 error</li>
</ul>
<pre>SQL&gt; ALTER INDEX t_d_virtual_idx RENAME TO t_d_virtual_idx2;
ALTER INDEX t_d_virtual_idx RENAME TO t_d_virtual_idx2
*
ERROR at line 1:
ORA-08114: can not alter a fake index</pre>
<ul>
<li>You can not create a fake index on same column list, but can create a conventional (real) index on same column list.</li>
</ul>
<pre>SQL&gt; CREATE INDEX t_d_virtual_idx3 ON t(d) NOSEGMENT;
CREATE INDEX t_d_virtual_idx3 ON t(d) NOSEGMENT
                                   *
ERROR at line 1:
ORA-01408: such column list already indexed

SQL&gt; CREATE INDEX t_d_virtual_idx4 ON t(d);

Index created.</pre>
<ul>
<li>You can analyze or collect statistics on fake indexes; However, no corresponding statistics will be populated</li>
</ul>
<pre>SQL&gt; EXECUTE DBMS_STATS.gather_index_stats(USER, 't_d_virtual_idx');

PL/SQL procedure successfully completed.</pre>
<div id="crp_related"><strong>Related Posts:</strong><ul><li><a href="http://perumal.org/bitmap-indexes-and-serialized-transactions/" rel="bookmark" class="crp_title">Bitmap Indexes and Serialized Transactions</a></li><li><a href="http://perumal.org/oracle-metadata-plan_table/" rel="bookmark" class="crp_title">Oracle Metadata: PLAN_TABLE</a></li><li><a href="http://perumal.org/analyzing-database-server-bottlenecks-using-vmstat/" rel="bookmark" class="crp_title">Analyzing Database Server Bottlenecks using VMSTAT</a></li><li><a href="http://perumal.org/analyzing-database-server-cpuprocessor-bottlenecks-using-mpstat/" rel="bookmark" class="crp_title">Analyzing Database Server CPU/Processor Bottlenecks using MPSTAT</a></li><li><a href="http://perumal.org/optimizer-index-access-paths-why-oracle-is-not-using-my-index/" rel="bookmark" class="crp_title">Optimizer Index Access Paths: Why Oracle is not using my Index?</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://perumal.org/virtual-nosegment-fake-indexes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ORION: Oracle I/O Numbers Calibration Tool in Oracle 11g R2</title>
		<link>http://perumal.org/orion-oracle-io-numbers-calibration-tool-in-oracle-11g-r2/</link>
		<comments>http://perumal.org/orion-oracle-io-numbers-calibration-tool-in-oracle-11g-r2/#comments</comments>
		<pubDate>Tue, 15 Dec 2009 03:18:55 +0000</pubDate>
		<dc:creator>Ramasundaram Perumal</dc:creator>
				<category><![CDATA[Oracle11g]]></category>
		<category><![CDATA[Tuning Tools & Advisors]]></category>
		<category><![CDATA[Utilities]]></category>
		<category><![CDATA[Advisors]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[Tuning]]></category>

		<guid isPermaLink="false">http://perumal.org/?p=453</guid>
		<description><![CDATA[ORION (Oracle I/O Calibration Tool) is a standalone tool for calibrating the I/O performance for storage systems that are intended to be used for Oracle databases. The calibration results are useful for understanding the performance capabilities of a storage system, either to uncover issues that would impact the performance of an Oracle database or to [...]]]></description>
			<content:encoded><![CDATA[<p>ORION (Oracle I/O Calibration Tool) is a standalone tool for calibrating the I/O performance for storage systems that are intended to be used for Oracle databases. The calibration results are useful for understanding the performance capabilities of a storage system, either to uncover issues that would impact the performance of an Oracle database or to size a new database installation. Since ORION is a standalone tool, the user is not required to create and run an Oracle database.</p>
<p>With the goal of closely mimicing the Oracle database, ORION generates a synthetic I/O workload, using the same I/O software stack as Oracle. ORION can be configured to generate a wide range of I/O workloads, including ones that simulate OLTP and data warehouse workloads.</p>
<p>A summary of how to use ORION is also available directly from ORION by invoking the &#8220;-help&#8221; option.</p>
<pre>$ orion -help
ORION: ORacle IO Numbers — Version 11.2.0.1.0

ORION runs IO performance tests that model Oracle RDBMS IO workloads.
It measures the performance of small (2-32K) IOs and large (128K+) IOs at various load levels.

Each Orion data point is a test for a specific mix of small and large IO loads sustained for a duration.
An Orion test consists of multiple data point tests.  These data point tests can be represented as a
two-dimensional matrix.  Each column in the matrix represents data point tests with the same small IO load,
but varying large IO loads. Each row represents data point tests with the same large IO load, but
varying small IO loads.  An Orion test can be for a single point, a single row, a single column, or
the whole matrix.

The ‘run’ parameter is the only mandatory parameter. Defaults are indicated for all other parameters.
For additional information on the user interface, see the Orion User Guide.

...output omitted...</pre>
<p>ORION tool for various OS platforms and user guide can be downloaded from  <a href="http://www.oracle.com/technology/software/tech/orion/index.html" target="_blank">Oracle ORION downloads</a>. Oracle offering this tool as a standalone download with an <em>unsupported</em> note.  I just noticed, Oracle has included this tool in Oracle 11g Release 2; the binary is located under <span style="font-family: courier new,courier;">$ORACLE_HOME/bin</span>.</p>
<div id="crp_related"><strong>Related Posts:</strong><ul><li><a href="http://perumal.org/oracle-statistics-package-statspack-a-free-performance-analysis-tool/" rel="bookmark" class="crp_title">Oracle Statistics Package (STATSPACK): A Free Performance Analysis Tool</a></li><li><a href="http://perumal.org/oracles-os-watcher-osw-utility/" rel="bookmark" class="crp_title">Oracle&#8217;s OS Watcher (OSW) Utility</a></li><li><a href="http://perumal.org/sql-developer-database-export-wizard-to-export-ddl-and-data-as-dml/" rel="bookmark" class="crp_title">SQL Developer: Database Export Wizard to export DDL and Data as DML</a></li><li><a href="http://perumal.org/identifying-cpu-and-memory-intensive-processes-on-a-database-server-using-ps/" rel="bookmark" class="crp_title">Identifying CPU and Memory Intensive processes on a database server using PS</a></li><li><a href="http://perumal.org/managing-software-packages-aka-rpms-with-yum/" rel="bookmark" class="crp_title">Managing Software Packages (aka RPMs) with Yum</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://perumal.org/orion-oracle-io-numbers-calibration-tool-in-oracle-11g-r2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Customizing TOAD SQL Explain Plan Content</title>
		<link>http://perumal.org/customizing-toad-sql-explain-plan-content/</link>
		<comments>http://perumal.org/customizing-toad-sql-explain-plan-content/#comments</comments>
		<pubDate>Thu, 19 Nov 2009 17:48:54 +0000</pubDate>
		<dc:creator>Ramasundaram Perumal</dc:creator>
				<category><![CDATA[Development Tools]]></category>
		<category><![CDATA[TOAD]]></category>

		<guid isPermaLink="false">http://perumal.org/?p=451</guid>
		<description><![CDATA[The default display of Explain Plan in TOAD SQL Editor has very basic information. 
Right-clicking on the explain plan and selecting &#8220;Adjust Content&#8221; from the context menu will bring &#8220;Execution Plan Preferences&#8221; window, which allows you to control the information displayed in the Explain Plan tab.
Related Posts:Removing table rows using an inline viewPlan Table and methods [...]]]></description>
			<content:encoded><![CDATA[<p>The default display of Explain Plan in TOAD SQL Editor has very basic information. </p>
<div id="attachment_452" class="wp-caption aligncenter" style="width: 783px"><img class="size-full wp-image-452" title="TOAD Explain Plan" src="http://perumal.org/wp-content/uploads/2009/11/Toad_Explain_Plan.JPG" alt="TOAD Explain Plan" width="773" height="342" /><p class="wp-caption-text">TOAD Explain Plan</p></div>
<p>Right-clicking on the explain plan and selecting &#8220;Adjust Content&#8221; from the context menu will bring &#8220;Execution Plan Preferences&#8221; window, which allows you to control the information displayed in the Explain Plan tab.</p>
<div id="attachment_450" class="wp-caption aligncenter" style="width: 464px"><img class="size-full wp-image-450" title="Toad Explain Plan &gt; Adjust_Content &gt; Execution Plan Preferences" src="http://perumal.org/wp-content/uploads/2009/11/Toad_Explain_Plan_Adjust_Content.JPG" alt="Toad Explain Plan &gt; Adjust Content &gt; Execution Plan Preferences" width="454" height="487" /><p class="wp-caption-text">Toad Explain Plan &gt; Adjust Content &gt; Execution Plan Preferences</p></div>
<div id="crp_related"><strong>Related Posts:</strong><ul><li><a href="http://perumal.org/removing-table-rows-using-an-inline-view/" rel="bookmark" class="crp_title">Removing table rows using an inline view</a></li><li><a href="http://perumal.org/plan-table-and-methods-for-obtaining-a-formatted-explain-plan/" rel="bookmark" class="crp_title">Plan Table and methods for obtaining a formatted Explain Plan</a></li><li><a href="http://perumal.org/how-to-read-an-oracle-sql-execution-plan/" rel="bookmark" class="crp_title">How to read an Oracle SQL Execution Plan?</a></li><li><a href="http://perumal.org/oracle-metadata-plan_table/" rel="bookmark" class="crp_title">Oracle Metadata: PLAN_TABLE</a></li><li><a href="http://perumal.org/virtual-nosegment-fake-indexes/" rel="bookmark" class="crp_title">Virtual / NOSEGMENT / Fake Indexes</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://perumal.org/customizing-toad-sql-explain-plan-content/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Optimizer Index Access Paths: Why Oracle is not using my Index?</title>
		<link>http://perumal.org/optimizer-index-access-paths-why-oracle-is-not-using-my-index/</link>
		<comments>http://perumal.org/optimizer-index-access-paths-why-oracle-is-not-using-my-index/#comments</comments>
		<pubDate>Wed, 11 Nov 2009 19:13:19 +0000</pubDate>
		<dc:creator>Ramasundaram Perumal</dc:creator>
				<category><![CDATA[Foundations]]></category>
		<category><![CDATA[Indexes]]></category>
		<category><![CDATA[Optimizer]]></category>
		<category><![CDATA[Oracle]]></category>
		<category><![CDATA[Oracle10g]]></category>
		<category><![CDATA[Oracle11g]]></category>
		<category><![CDATA[Tips & Techniques]]></category>
		<category><![CDATA[Techniques]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://perumal.org/?p=442</guid>
		<description><![CDATA[Access paths are ways in which data is retrieved from the database. In general, index access paths should be used for statements that retrieve a small subset of table rows, while full scans are more efficient when accessing a large portion of the table. Online transaction processing (OLTP) applications, which consist of short-running SQL statements [...]]]></description>
			<content:encoded><![CDATA[<p>Access paths are ways in which data is retrieved from the database. In general, index access paths should be used for statements that retrieve a small subset of table rows, while full scans are more efficient when accessing a large portion of the table. Online transaction processing (OLTP) applications, which consist of short-running SQL statements with high selectivity, often are characterized by the use of index access paths. Decision support systems, on the other hand, tend to use partitioned tables and perform full scans of the relevant partitions.</p>
<p>The optimizer chooses the access path based on the following factors:</p>
<ul>
<li>The available access paths for the statement</li>
<li>The estimated cost of executing the statement, using each access path or combination of paths</li>
</ul>
<p>In Index Scan method, a row is retrieved by traversing the index, using the indexed column values specified by the statement. An index scan retrieves data from an index based on the value of one or more columns in the index. To perform an index scan, Oracle searches the index for the indexed column values accessed by the statement. If the statement accesses only columns of the index, then Oracle reads the indexed column values directly from the index, rather than from the table.</p>
<p>The index contains not only the indexed value, but also the rowids of rows in the table having that value. Therefore, if the statement accesses other columns in addition to the indexed columns, then Oracle can find the rows in the table by using either a table access by rowid or a cluster scan.</p>
<pre>ops$rperumal@PDB10&gt; CREATE TABLE t (
  2    pkc NOT NULL,
  3    sv2,
  4    cv20,
  5    sv200,
  6    rsn1,
  7    rsn2,
  8    rsn3,
  9    data,
 10    CONSTRAINT t_pk primary key (pkc)
 11  )
 12  AS
 13  SELECT rownum                  pkc,
 14  	    mod(rownum, 2)+1	sv2,
 15  	    trunc((rownum-1)/500)	cv20,
 16  	    mod(rownum, 200)+1	sv200,
 17  	    rownum		rsn1,
 18  	    rownum		rsn2,
 19  	    rownum		rsn3,
 20  	    lpad(rownum,10,'0') 	data
 21  FROM dual
 22  CONNECT BY LEVEL &lt;= 10000;

Table created.

ops$rperumal@PDB10&gt; CREATE INDEX t_sv2_rsn1 ON t(sv2,rsn1);

Index created.

ops$rperumal@PDB10&gt; CREATE INDEX t_cv20_rsn2 ON t(cv20,rsn2);

Index created.

ops$rperumal@PDB10&gt; CREATE INDEX t_sv200_rsn3 ON t(sv200,rsn3);

Index created.

ops$rperumal@PDB10&gt; CREATE INDEX t_data ON t(data);

Index created.

ops$rperumal@PDB10&gt; EXECUTE DBMS_STATS.gather_table_stats(USER,'T',cascade=&gt;TRUE);

PL/SQL procedure successfully completed.

ops$rperumal@PDB10&gt; SET AUTOTRACE TRACEONLY EXPLAIN</pre>
<h4>Index Unique Scan</h4>
<p>This scan returns, at most, a single rowid. Oracle performs a unique scan if a statement contains a UNIQUE or a PRIMARY KEY constraint that guarantees that only a single row is accessed.  This access path is used when all columns of a unique (B-tree) index or an index created as a result of a primary key constraint are specified with equality conditions.</p>
<p>Execution plan using Index Unique Scan below:</p>
<pre>ops$rperumal@PDB10&gt; SELECT * FROM t WHERE pkc = 2000;

Execution Plan
----------------------------------------------------------
Plan hash value: 1303508680

------------------------------------------------------------------------------------
| Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |      |     1 |    36 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T    |     1 |    36 |     2   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | T_PK |     1 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("PKC"=2000)</pre>
<h4>Index Range Scan</h4>
<p>An index range scan is a common operation for accessing selective data. It can be bounded (bounded on both sides) or unbounded (on one or both sides). Data is returned in the ascending order of index columns. Multiple rows with identical values are sorted in ascending order by rowid. If data must be sorted by order, then use the ORDER BY clause, and do not rely on an index. If an index can be used to satisfy an ORDER BY clause, then the optimizer uses this option and avoids a sort.</p>
<p>The optimizer uses a range scan when it finds one or more leading columns of an index specified in conditions, such as the following:</p>
<ul>
<li>col1 = :b1</li>
<li>col1 &lt; :b1</li>
<li>col1 &gt; :b1</li>
<li>AND combination of the preceding conditions for leading columns in the index</li>
<li>col1 like &#8216;ASD%&#8217; wild-card searches should not be in a leading position otherwise the condition col1 like &#8216;%ASD&#8217; does not result in a range scan. Range scans can use unique or non-unique indexes. Range scans avoid sorting when index columns constitute the ORDER BY/GROUP BY clause.</li>
</ul>
<p>Execution plan usingIindex Range Scan below:</p>
<pre>ops$rperumal@PDB10&gt; SELECT *  FROM t WHERE pkc &lt; 200;

Execution Plan
----------------------------------------------------------
Plan hash value: 3772518221

------------------------------------------------------------------------------------
| Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |      |   199 |  7164 |     4   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T    |   199 |  7164 |     4   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | T_PK |   199 |       |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("PKC"&lt;200)

ops$rperumal@PDB10&gt; SELECT *  FROM t WHERE pkc &gt; 9900;

Execution Plan
----------------------------------------------------------
Plan hash value: 3772518221

------------------------------------------------------------------------------------
| Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |      |   100 |  3600 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T    |   100 |  3600 |     3   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | T_PK |   100 |       |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("PKC"&gt;9900)

ops$rperumal@PDB10&gt; SELECT *  FROM t WHERE pkc BETWEEN 2000 AND 3000;

Execution Plan
----------------------------------------------------------
Plan hash value: 3772518221

------------------------------------------------------------------------------------
| Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |      |  1002 | 36072 |    10   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T    |  1002 | 36072 |    10   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | T_PK |  1002 |       |     4   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("PKC"&gt;=2000 AND "PKC"&lt;=3000)

ops$rperumal@PDB10&gt; SELECT * FROM t WHERE data = '0000000001';

Execution Plan
----------------------------------------------------------
Plan hash value: 3782328437

--------------------------------------------------------------------------------------
| Id  | Operation                   | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |        |     1 |    36 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T      |     1 |    36 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | T_DATA |     1 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("DATA"='0000000001')</pre>
<h4>Index Range Scan Descending</h4>
<p>An index range scan descending is identical to an index range scan, except that the data is returned in descending order. Indexes, by default, are stored in ascending order. Usually, this scan is used when ordering data in a descending order to return the most recent data first, or when seeking a value less than a specified value. The optimizer uses index range scan descending when an order by descending clause can be satisfied by an index.</p>
<p>Execution plan using Index Range Scans Descending below:</p>
<pre>ops$rperumal@PDB10&gt; SELECT *  FROM t WHERE pkc BETWEEN 2000 AND 3000 ORDER BY pkc DESC;

Execution Plan
----------------------------------------------------------
Plan hash value: 725076093

-------------------------------------------------------------------------------------
| Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |  1002 | 36072 |    10   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID | T    |  1002 | 36072 |    10   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN DESCENDING| T_PK |  1002 |       |     4   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("PKC"&gt;=2000 AND "PKC"&lt;=3000)</pre>
<h4>Index Skip Scan</h4>
<p>Index skip scan improve index scans by nonprefix columns. Often, scanning index blocks is faster than scanning table data blocks. Skip scanning lets a composite index be split logically into smaller subindexes. In skip scanning, the initial column of the composite index is not specified in the query. In other words, it is skipped.</p>
<p>The number of logical subindexes is determined by the number of distinct values in the initial column. Skip scanning is advantageous if there are few distinct values in the leading column of the composite index and many distinct values in the nonleading key of the index.</p>
<p>Execution plan using Index Skip Scan below:</p>
<pre>ops$rperumal@PDB10&gt; SELECT *  FROM t WHERE rsn1 = 55;

Execution Plan
----------------------------------------------------------
Plan hash value: 2069911305

------------------------------------------------------------------------------------------
| Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |            |     1 |    36 |     4   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T          |     1 |    36 |     4   (0)| 00:00:01 |
|*  2 |   INDEX SKIP SCAN           | T_SV2_RSN1 |     1 |       |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("RSN1"=55)
       filter("RSN1"=55)

ops$rperumal@PDB10&gt; SELECT sv2,rsn1  FROM t WHERE rsn1 = 55;

Execution Plan
----------------------------------------------------------
Plan hash value: 714504825

-------------------------------------------------------------------------------
| Id  | Operation        | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |            |     1 |     7 |     3   (0)| 00:00:01 |
|*  1 |  INDEX SKIP SCAN | T_SV2_RSN1 |     1 |     7 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("RSN1"=55)
       filter("RSN1"=55)

ops$rperumal@PDB10&gt; SELECT data  FROM t WHERE rsn1 = 55;

Execution Plan
----------------------------------------------------------
Plan hash value: 2069911305

------------------------------------------------------------------------------------------
| Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |            |     1 |    15 |     4   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T          |     1 |    15 |     4   (0)| 00:00:01 |
|*  2 |   INDEX SKIP SCAN           | T_SV2_RSN1 |     1 |       |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("RSN1"=55)
       filter("RSN1"=55)</pre>
<h4>Index Full Scan</h4>
<p>A full index scan eliminates a sort operation, because the data is ordered by the index key. It reads the blocks singly. A full scan is used in any of the following situations:</p>
<ul>
<li>All of the columns in the ORDER BY clause must be in the index: The order of the columns in the ORDER BY clause must match the order of the leading index columns. The ORDER BY clause can contain all of the columns in the index or a subset of the columns in the index.</li>
<li>The query requires a sort merge join. A full index scan can be done instead of doing a full table scan followed by a sort if the query meets the following requirements: All of the columns referenced in the query must be in the index. The order of the columns referenced in the query must match the order of the leading index columns.</li>
<li>A GROUP BY clause is present in the query, and the columns in the GROUP BY clause are present in the index. The columns do not need to be in the same order in the index and the GROUP BY clause. The GROUP BY clause can contain all of the columns in the index or a subset of the columns in the index.</li>
</ul>
<p>Execution plan using Index Full Scan below:</p>
<pre>ops$rperumal@PDB10&gt; SELECT * FROM t ORDER BY pkc;

Execution Plan
----------------------------------------------------------
Plan hash value: 1399892806

------------------------------------------------------------------------------------
| Id  | Operation                   | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |      | 10000 |   351K|    80   (2)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T    | 10000 |   351K|    80   (2)| 00:00:01 |
|   2 |   INDEX FULL SCAN           | T_PK | 10000 |       |    21   (0)| 00:00:01 |
------------------------------------------------------------------------------------

ops$rperumal@PDB10&gt; SELECT pkc FROM t ORDER BY pkc;

Execution Plan
----------------------------------------------------------
Plan hash value: 2446862604

-------------------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT |      | 10000 | 40000 |    21   (0)| 00:00:01 |
|   1 |  INDEX FULL SCAN | T_PK | 10000 | 40000 |    21   (0)| 00:00:01 |
-------------------------------------------------------------------------</pre>
<h4>Index Fast Full Scan</h4>
<p>Index fast full scan is an alternative to a full table scan when the index contains all the columns that are needed for the query, and at least one column in the index key has the NOT NULL constraint. A fast full scan accesses the data in the index itself, without accessing the table. It cannot be used to eliminate a sort operation, because the data is not ordered by the index key.</p>
<p>Execution plan using Index Fast Full Scan below:</p>
<pre>ops$rperumal@PDB10&gt; SELECT cv20,rsn2  FROM t WHERE rsn2 = 55;

Execution Plan
----------------------------------------------------------
Plan hash value: 2742123628

------------------------------------------------------------------------------------
| Id  | Operation            | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |             |     1 |     7 |     7   (0)| 00:00:01 |
|*  1 |  INDEX FAST FULL SCAN| T_CV20_RSN2 |     1 |     7 |     7   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("RSN2"=55)</pre>
<h4>Why Oracle is not using my Index?</h4>
<p>There are many reasons that Oracle Optimizer will turn an Index access to Full table access. Some of the most common scenarios are:</p>
<h5>Case 1: Index Range Scan to Full Table Scan</h5>
<p>The optimizer does FTS if a large perentage of rows are read; usually over 5-20%, but this percentage can vary. Below example shows that an Index Range Scan turned into a Full Table scan upon requesting to retrieve 20% of the rows from a table.</p>
<pre>ops$rperumal@PDB10&gt; SELECT *  FROM t WHERE pkc &lt; 2000;

Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  1999 | 71964 |    15   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |  1999 | 71964 |    15   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("PKC"&lt;2000)

ops$rperumal@PDB10&gt; SELECT *  FROM t WHERE pkc &gt; 8000;

Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  2000 | 72000 |    15   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |  2000 | 72000 |    15   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("PKC"&gt;8000)

ops$rperumal@PDB10&gt; SELECT *  FROM t WHERE pkc BETWEEN 2000 AND 6000;

Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  4002 |   140K|    15   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |  4002 |   140K|    15   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("PKC"&lt;=6000 AND "PKC"&gt;=2000)

ops$rperumal@PDB10> SELECT * FROM t WHERE pkc <> 2000;

Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  9999 |   351K|    16   (7)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |  9999 |   351K|    16   (7)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("PKC"<>2000)
</pre>
<h5>Case 2: Index Skip Scan / Index Fast Full Scan  to Full Table Scan</h5>
<p>Optimizer performs a Index Skip Scan only if a leading edge of the index has very few distinct values and the optimizer is aware of that.  SV2 column in the test table has two distinct values, retrieving based on rsn1=55 uses index (T_SV2_RSN1), which results in Index Skip Scan. Whereas, CV2 column in the test table has 20 distinct values, retrieving based on rsn2=55 and selecting column that part of composite index (T_CV20_RSN2) , which results in Index Fast Full Scan. </p>
<ul>
<li>Index Skip Scan will turn into Full Table Scan when the leading edge of the index has many distinct values and you retrieve the data by non-leading index column.</li>
<li>Index Fast Full Scan will turn into Full Table Scan when you do not refer indexed columns in your query.</li>
</ul>
<p> </p>
<pre>ops$rperumal@PDB10&gt; SELECT *  FROM t WHERE rsn2 = 55;

Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |    36 |    15   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |     1 |    36 |    15   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("RSN2"=55)

ops$rperumal@PDB10&gt; SELECT cv20,rsn2, data  FROM t WHERE rsn2 = 55;

Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |    18 |    15   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |     1 |    18 |    15   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("RSN2"=55)</pre>
<h5> <br />
Case 3:  Implicit or Explict data type conversion to Number</h5>
<p>When you have a indexed character column and the column holds only numeric values,  following may turn index access to a full table scan.</p>
<pre>ops$rperumal@PDB10&gt; SELECT * FROM t WHERE data = 1;

Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |    36 |    16   (7)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |     1 |    36 |    16   (7)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(TO_NUMBER("DATA")=1)

ops$rperumal@PDB10&gt; SELECT * FROM t WHERE to_number(data)=1;

Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |    36 |    16   (7)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |     1 |    36 |    16   (7)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(TO_NUMBER("DATA")=1)</pre>
<h5>Case 4: Using function on an indexed column</h5>
<p>If you use a function on an indexed column similar to below then index will not be used unless there is a matching function based index.</p>
<pre>SELECT * FROM t WHERE your_function(data) = my_value</pre>
<h5>Case 5: Counting Records</h5>
<p>If you issue a query similar below and it has a B*Tree Index then no NULL records will make it into the index; Hence, the optimizer will do a Full Table Scan to get the count of rows.</p>
<pre>SELECT COUNT(*) FROM t</pre>
<h5>Case 6: Missing Statistics</h5>
<p>If the optimizer is not aware of the data then it will lead to incorrect cardinality; it could result in full table scans.</p>
<blockquote><p>You can not say &#8220;all full table scans are bad and all indexes are good&#8221; &#8211; It depends your data and what question thats been asked.</p></blockquote>
<div id="crp_related"><strong>Related Posts:</strong><ul><li><a href="http://perumal.org/virtual-nosegment-fake-indexes/" rel="bookmark" class="crp_title">Virtual / NOSEGMENT / Fake Indexes</a></li><li><a href="http://perumal.org/removing-table-rows-using-an-inline-view/" rel="bookmark" class="crp_title">Removing table rows using an inline view</a></li><li><a href="http://perumal.org/how-to-read-an-oracle-sql-execution-plan/" rel="bookmark" class="crp_title">How to read an Oracle SQL Execution Plan?</a></li><li><a href="http://perumal.org/dbms_xplandisplay_cursor-does-not-display-execution-plan-of-all-children-associated-with-the-sql_id/" rel="bookmark" class="crp_title">DBMS_XPLAN.DISPLAY_CURSOR does not display execution plan of all children associated with the SQL_ID</a></li><li><a href="http://perumal.org/oracle-metadata-plan_table/" rel="bookmark" class="crp_title">Oracle Metadata: PLAN_TABLE</a></li></ul></div>]]></content:encoded>
			<wfw:commentRss>http://perumal.org/optimizer-index-access-paths-why-oracle-is-not-using-my-index/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
