<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	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:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
		>
<channel>
	<title>Comments on: True or False &#8211; Why Isn&#8217;t My Index Getting Used?</title>
	<atom:link href="http://hoopercharles.wordpress.com/2010/05/25/true-or-false-why-isnt-my-index-getting-used/feed/" rel="self" type="application/rss+xml" />
	<link>http://hoopercharles.wordpress.com/2010/05/25/true-or-false-why-isnt-my-index-getting-used/</link>
	<description>Miscellaneous Random Oracle Topics: Stop, Think, ... Understand</description>
	<lastBuildDate>Thu, 13 Jun 2013 22:46:43 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
	<item>
		<title>By: joel garry</title>
		<link>http://hoopercharles.wordpress.com/2010/05/25/true-or-false-why-isnt-my-index-getting-used/#comment-1175</link>
		<dc:creator><![CDATA[joel garry]]></dc:creator>
		<pubDate>Wed, 26 May 2010 18:25:03 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=2429#comment-1175</guid>
		<description><![CDATA[This has been bothering me about exadata since it was announced; if the db optimizer can&#039;t get always get the best plan, why would we expect a hardware filter to do any better?  This seems more fundamental to me than, say, people being sloppier with their programming because they can brute-force with hardware.

I&#039;ve been thinking about this a lot since I have a situation where a report generator spits out sql that causes the db to create a view and doesn&#039;t push predicates up into the view, leading to full table scans within nested loops.  So adding the really obvious index has no effect.  Every time I run into this kind of thing I slap my forehead, it&#039;s going to be a lot of work one way or another, can&#039;t just hack some hints.  The thought of an outlines solution gives me nightmares like comment #8 on http://jonathanlewis.wordpress.com/2008/02/17/pushing-predicates-2/ .  Wondering why this doesn&#039;t happen on similar processes leads me to discover it does, just no one has complained yet, users leave orphaned processes running, thinking they&#039;ve canceled them.

If it were just me, no one would care.  But I&#039;m pretty sure I&#039;m not the only one working on enterprise software with these kinds of issues.]]></description>
		<content:encoded><![CDATA[<p>This has been bothering me about exadata since it was announced; if the db optimizer can&#8217;t get always get the best plan, why would we expect a hardware filter to do any better?  This seems more fundamental to me than, say, people being sloppier with their programming because they can brute-force with hardware.</p>
<p>I&#8217;ve been thinking about this a lot since I have a situation where a report generator spits out sql that causes the db to create a view and doesn&#8217;t push predicates up into the view, leading to full table scans within nested loops.  So adding the really obvious index has no effect.  Every time I run into this kind of thing I slap my forehead, it&#8217;s going to be a lot of work one way or another, can&#8217;t just hack some hints.  The thought of an outlines solution gives me nightmares like comment #8 on <a href="http://jonathanlewis.wordpress.com/2008/02/17/pushing-predicates-2/" rel="nofollow">http://jonathanlewis.wordpress.com/2008/02/17/pushing-predicates-2/</a> .  Wondering why this doesn&#8217;t happen on similar processes leads me to discover it does, just no one has complained yet, users leave orphaned processes running, thinking they&#8217;ve canceled them.</p>
<p>If it were just me, no one would care.  But I&#8217;m pretty sure I&#8217;m not the only one working on enterprise software with these kinds of issues.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Donatello Settembrino</title>
		<link>http://hoopercharles.wordpress.com/2010/05/25/true-or-false-why-isnt-my-index-getting-used/#comment-1173</link>
		<dc:creator><![CDATA[Donatello Settembrino]]></dc:creator>
		<pubDate>Wed, 26 May 2010 14:59:31 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=2429#comment-1173</guid>
		<description><![CDATA[yes,
missing piece


CREATE INDEX TAB1_IX1 ON TAB1(N1);
CREATE INDEX TAB2_IX1 ON TAB2(N1);

thanks]]></description>
		<content:encoded><![CDATA[<p>yes,<br />
missing piece</p>
<p>CREATE INDEX TAB1_IX1 ON TAB1(N1);<br />
CREATE INDEX TAB2_IX1 ON TAB2(N1);</p>
<p>thanks</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Charles Hooper</title>
		<link>http://hoopercharles.wordpress.com/2010/05/25/true-or-false-why-isnt-my-index-getting-used/#comment-1171</link>
		<dc:creator><![CDATA[Charles Hooper]]></dc:creator>
		<pubDate>Wed, 26 May 2010 13:02:13 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=2429#comment-1171</guid>
		<description><![CDATA[Centinul,

Your answer is better than the one that I had in mind.  The next line after your first quote of the documentation reference explains why the conversion is performed in only one direction: CHARACTER--&gt;NUMBER.  Here is an example:
&lt;pre&gt;
CREATE TABLE T3(
  CHAR_COL VARCHAR2(10),
  C2 VARCHAR2(100),
  PRIMARY KEY (CHAR_COL));
 
INSERT INTO T3 VALUES(&#039;1&#039;,&#039;A&#039;);
INSERT INTO T3 VALUES(&#039;1.0&#039;,&#039;A&#039;);
INSERT INTO T3 VALUES(&#039;1.00&#039;,&#039;A&#039;);
INSERT INTO T3 VALUES(&#039;1.000&#039;,&#039;A&#039;);
INSERT INTO T3 VALUES(&#039;1.0000&#039;,&#039;A&#039;);
INSERT INTO T3 VALUES(&#039;1.00000&#039;,&#039;A&#039;);
INSERT INTO T3 VALUES(&#039;1.000000&#039;,&#039;A&#039;);
INSERT INTO T3 VALUES(&#039;1.0000000&#039;,&#039;A&#039;);
INSERT INTO T3 VALUES(&#039;1.00000000&#039;,&#039;A&#039;);
 
COMMIT;
&lt;/pre&gt;

Now consider the following - should all three queries return the same set of rows:
&lt;pre&gt;
SELECT
  *
FROM
  T3
WHERE
  CHAR_COL=1;
 
CHAR_COL   C2
---------- -----
1          A
1.0        A
1.00       A
1.000      A
1.0000     A
1.00000    A
1.000000   A
1.0000000  A
1.00000000 A
 
9 rows selected.
 
---
 
SELECT
  *
FROM
  T3
WHERE
  TO_NUMBER(CHAR_COL)=1;
 
CHAR_COL   C2
---------- -----
1          A
1.0        A
1.00       A
1.000      A
1.0000     A
1.00000    A
1.000000   A
1.0000000  A
1.00000000 A
 
9 rows selected.
 
---
 
SELECT
  *
FROM
  T3
WHERE
  CHAR_COL=TO_CHAR(1);
 
CHAR_COL   C2
---------- -----
1          A
&lt;/pre&gt;

If the number was automatically converted by Oracle into a character value, it might need to test a nearly infinite number of 0 characters appended to the end of the converted value after the decimal point (up to the number of characters of precision) for a matching result - this is avoided by converting the character value to a number.

I did not have that exact answer in mind until I saw the documentation reference that you provided.]]></description>
		<content:encoded><![CDATA[<p>Centinul,</p>
<p>Your answer is better than the one that I had in mind.  The next line after your first quote of the documentation reference explains why the conversion is performed in only one direction: CHARACTER&#8211;&gt;NUMBER.  Here is an example:</p>
<pre>
CREATE TABLE T3(
  CHAR_COL VARCHAR2(10),
  C2 VARCHAR2(100),
  PRIMARY KEY (CHAR_COL));
 
INSERT INTO T3 VALUES('1','A');
INSERT INTO T3 VALUES('1.0','A');
INSERT INTO T3 VALUES('1.00','A');
INSERT INTO T3 VALUES('1.000','A');
INSERT INTO T3 VALUES('1.0000','A');
INSERT INTO T3 VALUES('1.00000','A');
INSERT INTO T3 VALUES('1.000000','A');
INSERT INTO T3 VALUES('1.0000000','A');
INSERT INTO T3 VALUES('1.00000000','A');
 
COMMIT;
</pre>
<p>Now consider the following &#8211; should all three queries return the same set of rows:</p>
<pre>
SELECT
  *
FROM
  T3
WHERE
  CHAR_COL=1;
 
CHAR_COL   C2
---------- -----
1          A
1.0        A
1.00       A
1.000      A
1.0000     A
1.00000    A
1.000000   A
1.0000000  A
1.00000000 A
 
9 rows selected.
 
---
 
SELECT
  *
FROM
  T3
WHERE
  TO_NUMBER(CHAR_COL)=1;
 
CHAR_COL   C2
---------- -----
1          A
1.0        A
1.00       A
1.000      A
1.0000     A
1.00000    A
1.000000   A
1.0000000  A
1.00000000 A
 
9 rows selected.
 
---
 
SELECT
  *
FROM
  T3
WHERE
  CHAR_COL=TO_CHAR(1);
 
CHAR_COL   C2
---------- -----
1          A
</pre>
<p>If the number was automatically converted by Oracle into a character value, it might need to test a nearly infinite number of 0 characters appended to the end of the converted value after the decimal point (up to the number of characters of precision) for a matching result &#8211; this is avoided by converting the character value to a number.</p>
<p>I did not have that exact answer in mind until I saw the documentation reference that you provided.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Centinul</title>
		<link>http://hoopercharles.wordpress.com/2010/05/25/true-or-false-why-isnt-my-index-getting-used/#comment-1169</link>
		<dc:creator><![CDATA[Centinul]]></dc:creator>
		<pubDate>Wed, 26 May 2010 11:29:19 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=2429#comment-1169</guid>
		<description><![CDATA[&quot;Fun bonus question. Why is there an implicit datatype conversion of the table’s column in the first test case (table T1), but instead an implicit datatype conversion of the constant in the second test case (table T2).&quot;

If I had to wager a guess I would say this is due to the implicit data conversion rules outlined in the SQL Reference Manual (11.1):

http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/sql_elements002.htm#i163326

It states:

&quot;When comparing a character value with a numeric value, Oracle converts the character data to a numeric value.&quot;

In the first case since the column, CHAR_COL is a VARCHAR2 type and it is being compared to a constant of the NUMBER data type Oracle converts the column value to a NUMBER. This is also seen in the Predicate Information section.

In the second case the column value is a NUMBER data type and it is being compared to a constant of the VARCHAR2 data type. Therefore the constant is then converted to a NUMBER, leaving the NUM_COL unaffected from data type conversion.

Interestingly enough Oracle also states the following in the SQL Reference Manual:

&quot;Algorithms for implicit conversion are subject to change across software releases and among Oracle products. Behavior of explicit conversions is more predictable.&quot;]]></description>
		<content:encoded><![CDATA[<p>&#8220;Fun bonus question. Why is there an implicit datatype conversion of the table’s column in the first test case (table T1), but instead an implicit datatype conversion of the constant in the second test case (table T2).&#8221;</p>
<p>If I had to wager a guess I would say this is due to the implicit data conversion rules outlined in the SQL Reference Manual (11.1):</p>
<p><a href="http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/sql_elements002.htm#i163326" rel="nofollow">http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/sql_elements002.htm#i163326</a></p>
<p>It states:</p>
<p>&#8220;When comparing a character value with a numeric value, Oracle converts the character data to a numeric value.&#8221;</p>
<p>In the first case since the column, CHAR_COL is a VARCHAR2 type and it is being compared to a constant of the NUMBER data type Oracle converts the column value to a NUMBER. This is also seen in the Predicate Information section.</p>
<p>In the second case the column value is a NUMBER data type and it is being compared to a constant of the VARCHAR2 data type. Therefore the constant is then converted to a NUMBER, leaving the NUM_COL unaffected from data type conversion.</p>
<p>Interestingly enough Oracle also states the following in the SQL Reference Manual:</p>
<p>&#8220;Algorithms for implicit conversion are subject to change across software releases and among Oracle products. Behavior of explicit conversions is more predictable.&#8221;</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Charles Hooper</title>
		<link>http://hoopercharles.wordpress.com/2010/05/25/true-or-false-why-isnt-my-index-getting-used/#comment-1167</link>
		<dc:creator><![CDATA[Charles Hooper]]></dc:creator>
		<pubDate>Wed, 26 May 2010 11:16:37 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=2429#comment-1167</guid>
		<description><![CDATA[Jimmy,

Good point.

Immediately after I saw your post I realized that the statement to which you replied in my comment (Fun bonus question) could be read two different ways.  After seeing your post I replaced &quot;and&quot; with &quot;, but instead&quot; so that I could clarify that I was seeking the reason why the two cases were treated &lt;em&gt;differently&lt;/em&gt;, rather than suggesting that they were both the &lt;em&gt;same&lt;/em&gt; because they both had a similar problem (apples to oranges comparison - an implicit data type conversion as you correctly stated).  I am sorry if this change caused confusion.

The link to the 10053 trace file now works if someone would like to take a peek.]]></description>
		<content:encoded><![CDATA[<p>Jimmy,</p>
<p>Good point.</p>
<p>Immediately after I saw your post I realized that the statement to which you replied in my comment (Fun bonus question) could be read two different ways.  After seeing your post I replaced &#8220;and&#8221; with &#8220;, but instead&#8221; so that I could clarify that I was seeking the reason why the two cases were treated <em>differently</em>, rather than suggesting that they were both the <em>same</em> because they both had a similar problem (apples to oranges comparison &#8211; an implicit data type conversion as you correctly stated).  I am sorry if this change caused confusion.</p>
<p>The link to the 10053 trace file now works if someone would like to take a peek.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Donatello Settembrino</title>
		<link>http://hoopercharles.wordpress.com/2010/05/25/true-or-false-why-isnt-my-index-getting-used/#comment-1166</link>
		<dc:creator><![CDATA[Donatello Settembrino]]></dc:creator>
		<pubDate>Wed, 26 May 2010 10:56:21 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=2429#comment-1166</guid>
		<description><![CDATA[Yes, my test case is also suitable response Taral

I had not seen the answer on the clustering factor of Taral


thanks]]></description>
		<content:encoded><![CDATA[<p>Yes, my test case is also suitable response Taral</p>
<p>I had not seen the answer on the clustering factor of Taral</p>
<p>thanks</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Charles Hooper</title>
		<link>http://hoopercharles.wordpress.com/2010/05/25/true-or-false-why-isnt-my-index-getting-used/#comment-1165</link>
		<dc:creator><![CDATA[Charles Hooper]]></dc:creator>
		<pubDate>Wed, 26 May 2010 10:24:00 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=2429#comment-1165</guid>
		<description><![CDATA[Donatello,

A portion of your post between &quot;WHERE ROWNUM&quot; and  &quot;SELECT * FROM TAB1 WHERE N1 = 100;&quot; disappeared when you posted it.  I tried to recreate/fix that section of your post.  Thank you for posting a test case for the data distribution possibility.

I believe that this test case is also suitable for Taral&#039;s &quot;Clustering Factor&quot; answer.]]></description>
		<content:encoded><![CDATA[<p>Donatello,</p>
<p>A portion of your post between &#8220;WHERE ROWNUM&#8221; and  &#8220;SELECT * FROM TAB1 WHERE N1 = 100;&#8221; disappeared when you posted it.  I tried to recreate/fix that section of your post.  Thank you for posting a test case for the data distribution possibility.</p>
<p>I believe that this test case is also suitable for Taral&#8217;s &#8220;Clustering Factor&#8221; answer.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Donatello Settembrino</title>
		<link>http://hoopercharles.wordpress.com/2010/05/25/true-or-false-why-isnt-my-index-getting-used/#comment-1163</link>
		<dc:creator><![CDATA[Donatello Settembrino]]></dc:creator>
		<pubDate>Wed, 26 May 2010 08:22:24 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=2429#comment-1163</guid>
		<description><![CDATA[There may be also the following reasons:

1) usage hint NO_INDEX

2) modification parameter OPTIMIZER_INDEX_COST_ADJ

3) Data Distribution

&lt;pre&gt;
CREATE TABLE TAB1 AS
SELECT TO_CHAR(ROWNUM) AS C1 
     , trunc((ROWNUM-1) / 10) N1
     , rownum * 10 N2
     , ROWNUM      N3
     , sysdate     d1 
FROM ALL_OBJECTS
WHERE ROWNUM &lt;= 10000;


CREATE TABLE TAB2 AS
SELECT TO_CHAR(ROWNUM) AS C1 
     , MOD(ROWNUM, 1000) N1
     , rownum * 10 N2
     , ROWNUM      N3
     , sysdate     d1 
FROM ALL_OBJECTS
WHERE ROWNUM &lt;= 10000;
 
CREATE INDEX TAB1_IX1 ON TAB1(N1);
CREATE INDEX TAB2_IX1 ON TAB2(N1);

EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=&gt;USER, TABNAME=&gt;&#039;TAB1&#039;, CASCADE=&gt;TRUE)
EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=&gt;USER, TABNAME=&gt;&#039;TAB2&#039;, CASCADE=&gt;TRUE)

SELECT * FROM TAB1 WHERE N1 = 100;



-----------------------------------------------------------------------------
&#124; Id  &#124; Operation                   &#124; Name     &#124; Rows  &#124; Bytes &#124; Cost (%CPU)&#124;
-----------------------------------------------------------------------------
&#124;   0 &#124; SELECT STATEMENT            &#124;          &#124;    10 &#124;   260 &#124;     2   (0)&#124;
&#124;   1 &#124;  TABLE ACCESS BY INDEX ROWID&#124; TAB1     &#124;    10 &#124;   260 &#124;     2   (0)&#124;
&#124;   2 &#124;   INDEX RANGE SCAN          &#124; TAB1_IX1 &#124;    10 &#124;       &#124;     1   (0)&#124;
-----------------------------------------------------------------------------


SQL&gt; SELECT * FROM TAB2 WHERE N1 = 100;


---------------------------------------------------------------
&#124; Id  &#124; Operation         &#124; Name &#124; Rows  &#124; Bytes &#124; Cost (%CPU)&#124;
---------------------------------------------------------------
&#124;   0 &#124; SELECT STATEMENT  &#124;      &#124;    10 &#124;   260 &#124;    10   (0)&#124;
&#124;   1 &#124;  TABLE ACCESS FULL&#124; TAB2 &#124;    10 &#124;   260 &#124;    10   (0)&#124;
---------------------------------------------------------------
&lt;/pre&gt;]]></description>
		<content:encoded><![CDATA[<p>There may be also the following reasons:</p>
<p>1) usage hint NO_INDEX</p>
<p>2) modification parameter OPTIMIZER_INDEX_COST_ADJ</p>
<p>3) Data Distribution</p>
<pre>
CREATE TABLE TAB1 AS
SELECT TO_CHAR(ROWNUM) AS C1 
     , trunc((ROWNUM-1) / 10) N1
     , rownum * 10 N2
     , ROWNUM      N3
     , sysdate     d1 
FROM ALL_OBJECTS
WHERE ROWNUM &lt;= 10000;


CREATE TABLE TAB2 AS
SELECT TO_CHAR(ROWNUM) AS C1 
     , MOD(ROWNUM, 1000) N1
     , rownum * 10 N2
     , ROWNUM      N3
     , sysdate     d1 
FROM ALL_OBJECTS
WHERE ROWNUM &lt;= 10000;
 
CREATE INDEX TAB1_IX1 ON TAB1(N1);
CREATE INDEX TAB2_IX1 ON TAB2(N1);

EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=&gt;USER, TABNAME=&gt;'TAB1', CASCADE=&gt;TRUE)
EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=&gt;USER, TABNAME=&gt;'TAB2', CASCADE=&gt;TRUE)

SELECT * FROM TAB1 WHERE N1 = 100;



-----------------------------------------------------------------------------
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)|
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |    10 |   260 |     2   (0)|
|   1 |  TABLE ACCESS BY INDEX ROWID| TAB1     |    10 |   260 |     2   (0)|
|   2 |   INDEX RANGE SCAN          | TAB1_IX1 |    10 |       |     1   (0)|
-----------------------------------------------------------------------------


SQL&gt; SELECT * FROM TAB2 WHERE N1 = 100;


---------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)|
---------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |    10 |   260 |    10   (0)|
|   1 |  TABLE ACCESS FULL| TAB2 |    10 |   260 |    10   (0)|
---------------------------------------------------------------
</pre>
]]></content:encoded>
	</item>
	<item>
		<title>By: Jimmy</title>
		<link>http://hoopercharles.wordpress.com/2010/05/25/true-or-false-why-isnt-my-index-getting-used/#comment-1159</link>
		<dc:creator><![CDATA[Jimmy]]></dc:creator>
		<pubDate>Wed, 26 May 2010 01:07:46 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=2429#comment-1159</guid>
		<description><![CDATA[In both scenarios you are asking Oracle to compare apples to oranges. Varchar2 to Number, and vice versa.

I saw Tom Kyte at OOW last year do a presentation on the importance of metadata. One of his examples showed why it is important to store numbers as number data type, dates as date data type and strings as varchar2 data type. And how not doing so really messes up the CBO.]]></description>
		<content:encoded><![CDATA[<p>In both scenarios you are asking Oracle to compare apples to oranges. Varchar2 to Number, and vice versa.</p>
<p>I saw Tom Kyte at OOW last year do a presentation on the importance of metadata. One of his examples showed why it is important to store numbers as number data type, dates as date data type and strings as varchar2 data type. And how not doing so really messes up the CBO.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Charles Hooper</title>
		<link>http://hoopercharles.wordpress.com/2010/05/25/true-or-false-why-isnt-my-index-getting-used/#comment-1157</link>
		<dc:creator><![CDATA[Charles Hooper]]></dc:creator>
		<pubDate>Tue, 25 May 2010 23:35:20 +0000</pubDate>
		<guid isPermaLink="false">http://hoopercharles.wordpress.com/?p=2429#comment-1157</guid>
		<description><![CDATA[Let&#039;s see if I can cause a little bit of temporary confusion (or at least a stop and think moment).  I re-ran the above test on another box with Oracle Database 11.1.0.7 installed and receive some unexpected results.  Look!  Oracle&#039;s optimizer did not automatically select the cheapest plan until an index hint was supplied... the obvious conclusion?
&lt;pre&gt;
CREATE TABLE T1 (
  CHAR_COL VARCHAR2(10),
  C2 VARCHAR2(100),
  PRIMARY KEY (CHAR_COL));
 
INSERT INTO
  T1
SELECT
  TO_CHAR(ROWNUM),
  RPAD(&#039;A&#039;,100,&#039;A&#039;)
FROM
  DUAL
CONNECT BY
  LEVEL &lt;=1000000;
 
COMMIT;
 
EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=&gt;USER,TABNAME=&gt;&#039;T1&#039;,CASCADE=&gt;TRUE)
 
SET AUTOTRACE TRACEONLY EXPLAIN
 
SELECT
  *
FROM
  T1
WHERE
  CHAR_COL = 10;
 
Execution Plan
----------------------------------------------------------
Plan hash value: 3617692013
 
--------------------------------------------------------------------------
&#124; Id  &#124; Operation         &#124; Name &#124; Rows  &#124; Bytes &#124; Cost (%CPU)&#124; Time     &#124;
--------------------------------------------------------------------------
&#124;   0 &#124; SELECT STATEMENT  &#124;      &#124;     1 &#124;   107 &#124;  4416   (1)&#124; 00:00:53 &#124;
&#124;*  1 &#124;  TABLE ACCESS FULL&#124; T1   &#124;     1 &#124;   107 &#124;  4416   (1)&#124; 00:00:53 &#124;
--------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(TO_NUMBER(&quot;CHAR_COL&quot;)=10)
&lt;/pre&gt;
Notice the cost in the above is 4,416 with a predicted time of 53 seconds.  Now look what happens when the access path is hinted (force, if possible) to use an index access path:
&lt;pre&gt; 
SELECT /*+ INDEX(T1) */
  *
FROM
  T1
WHERE
  CHAR_COL = 10;
 
Execution Plan
----------------------------------------------------------
Plan hash value: 2890641821
 
--------------------------------------------------------------------------------------------
&#124; Id  &#124; Operation                   &#124; Name         &#124; Rows  &#124; Bytes &#124; Cost (%CPU)&#124; Time     &#124;
--------------------------------------------------------------------------------------------
&#124;   0 &#124; SELECT STATEMENT            &#124;              &#124;     1 &#124;   107 &#124;  3930   (1)&#124; 00:00:48 &#124;
&#124;   1 &#124;  TABLE ACCESS BY INDEX ROWID&#124; T1           &#124;     1 &#124;   107 &#124;  3930   (1)&#124; 00:00:48 &#124;
&#124;*  2 &#124;   INDEX FULL SCAN           &#124; SYS_C0030633 &#124;     1 &#124;       &#124;  3929   (1)&#124; 00:00:48 &#124;
--------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(TO_NUMBER(&quot;CHAR_COL&quot;)=10)
&lt;/pre&gt;

A lower calculated cost and a lower calculated execution time.  Must be that...

The optimizer parameters, for the most part, are the Oracle Database defaults:
&lt;pre&gt;
SET AUTOTRACE OFF
SHOW PARAMETER OPTIMIZER
  
NAME                                 TYPE        VALUE
------------------------------------ ----------- --------
optimizer_capture_sql_plan_baselines boolean     FALSE
optimizer_dynamic_sampling           integer     2
optimizer_features_enable            string      11.1.0.7
optimizer_index_caching              integer     0
optimizer_index_cost_adj             integer     100
optimizer_mode                       string      ALL_ROWS
optimizer_secure_view_merging        boolean     TRUE
optimizer_use_invisible_indexes      boolean     FALSE
optimizer_use_pending_statistics     boolean     FALSE
optimizer_use_sql_plan_baselines     boolean     TRUE
&lt;/pre&gt;
(10053 trace file for test case &lt;a href=&quot;http://hoopercharles.files.wordpress.com/2010/05/or11_ora_4400_whyfulltablescantest.pdf&quot; rel=&quot;nofollow&quot;&gt;OR11_ora_4400_WhyFullTableScanTest.trc&lt;/a&gt; edit: link to the trace file is fixed)
----
 
Let&#039;s try one more test.  This time we will define a column as NUMBER and try essentially the same test, just with a WHERE clause with a string (VARCHAR2) specified as a predicate in the WHERE clause:
&lt;pre&gt;
CREATE TABLE T2 (
  NUM_COL NUMBER,
  C2 VARCHAR2(100),
  PRIMARY KEY (NUM_COL));

INSERT INTO
  T2
SELECT
  ROWNUM,
  RPAD(&#039;A&#039;,100,&#039;A&#039;)
FROM
  DUAL
CONNECT BY
  LEVEL &lt;=1000000;

COMMIT;

EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=&gt;USER,TABNAME=&gt;&#039;T2&#039;,CASCADE=&gt;TRUE)

SET AUTOTRACE TRACEONLY EXPLAIN

SELECT
  *
FROM
  T2
WHERE
  NUM_COL = &#039;10&#039;;
 
Execution Plan
----------------------------------------------------------
Plan hash value: 621649307

--------------------------------------------------------------------------------------------
&#124; Id  &#124; Operation                   &#124; Name         &#124; Rows  &#124; Bytes &#124; Cost (%CPU)&#124; Time     &#124;
--------------------------------------------------------------------------------------------
&#124;   0 &#124; SELECT STATEMENT            &#124;              &#124;     1 &#124;   105 &#124;     3   (0)&#124; 00:00:01 &#124;
&#124;   1 &#124;  TABLE ACCESS BY INDEX ROWID&#124; T2           &#124;     1 &#124;   105 &#124;     3   (0)&#124; 00:00:01 &#124;
&#124;*  2 &#124;   INDEX UNIQUE SCAN         &#124; SYS_C0030634 &#124;     1 &#124;       &#124;     2   (0)&#124; 00:00:01 &#124;
--------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access(&quot;NUM_COL&quot;=10)
&lt;/pre&gt;

Fun bonus question.  Why is there an implicit datatype conversion of the table&#039;s column in the first test case (table T1), but instead an implicit datatype conversion of the constant in the second test case (table T2).]]></description>
		<content:encoded><![CDATA[<p>Let&#8217;s see if I can cause a little bit of temporary confusion (or at least a stop and think moment).  I re-ran the above test on another box with Oracle Database 11.1.0.7 installed and receive some unexpected results.  Look!  Oracle&#8217;s optimizer did not automatically select the cheapest plan until an index hint was supplied&#8230; the obvious conclusion?</p>
<pre>
CREATE TABLE T1 (
  CHAR_COL VARCHAR2(10),
  C2 VARCHAR2(100),
  PRIMARY KEY (CHAR_COL));
 
INSERT INTO
  T1
SELECT
  TO_CHAR(ROWNUM),
  RPAD('A',100,'A')
FROM
  DUAL
CONNECT BY
  LEVEL &lt;=1000000;
 
COMMIT;
 
EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=&gt;USER,TABNAME=&gt;'T1',CASCADE=&gt;TRUE)
 
SET AUTOTRACE TRACEONLY EXPLAIN
 
SELECT
  *
FROM
  T1
WHERE
  CHAR_COL = 10;
 
Execution Plan
----------------------------------------------------------
Plan hash value: 3617692013
 
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |   107 |  4416   (1)| 00:00:53 |
|*  1 |  TABLE ACCESS FULL| T1   |     1 |   107 |  4416   (1)| 00:00:53 |
--------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(TO_NUMBER("CHAR_COL")=10)
</pre>
<p>Notice the cost in the above is 4,416 with a predicted time of 53 seconds.  Now look what happens when the access path is hinted (force, if possible) to use an index access path:</p>
<pre> 
SELECT /*+ INDEX(T1) */
  *
FROM
  T1
WHERE
  CHAR_COL = 10;
 
Execution Plan
----------------------------------------------------------
Plan hash value: 2890641821
 
--------------------------------------------------------------------------------------------
| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |              |     1 |   107 |  3930   (1)| 00:00:48 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T1           |     1 |   107 |  3930   (1)| 00:00:48 |
|*  2 |   INDEX FULL SCAN           | SYS_C0030633 |     1 |       |  3929   (1)| 00:00:48 |
--------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(TO_NUMBER("CHAR_COL")=10)
</pre>
<p>A lower calculated cost and a lower calculated execution time.  Must be that&#8230;</p>
<p>The optimizer parameters, for the most part, are the Oracle Database defaults:</p>
<pre>
SET AUTOTRACE OFF
SHOW PARAMETER OPTIMIZER
  
NAME                                 TYPE        VALUE
------------------------------------ ----------- --------
optimizer_capture_sql_plan_baselines boolean     FALSE
optimizer_dynamic_sampling           integer     2
optimizer_features_enable            string      11.1.0.7
optimizer_index_caching              integer     0
optimizer_index_cost_adj             integer     100
optimizer_mode                       string      ALL_ROWS
optimizer_secure_view_merging        boolean     TRUE
optimizer_use_invisible_indexes      boolean     FALSE
optimizer_use_pending_statistics     boolean     FALSE
optimizer_use_sql_plan_baselines     boolean     TRUE
</pre>
<p>(10053 trace file for test case <a href="http://hoopercharles.files.wordpress.com/2010/05/or11_ora_4400_whyfulltablescantest.pdf" rel="nofollow">OR11_ora_4400_WhyFullTableScanTest.trc</a> edit: link to the trace file is fixed)<br />
&#8212;-</p>
<p>Let&#8217;s try one more test.  This time we will define a column as NUMBER and try essentially the same test, just with a WHERE clause with a string (VARCHAR2) specified as a predicate in the WHERE clause:</p>
<pre>
CREATE TABLE T2 (
  NUM_COL NUMBER,
  C2 VARCHAR2(100),
  PRIMARY KEY (NUM_COL));

INSERT INTO
  T2
SELECT
  ROWNUM,
  RPAD('A',100,'A')
FROM
  DUAL
CONNECT BY
  LEVEL &lt;=1000000;

COMMIT;

EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=&gt;USER,TABNAME=&gt;'T2',CASCADE=&gt;TRUE)

SET AUTOTRACE TRACEONLY EXPLAIN

SELECT
  *
FROM
  T2
WHERE
  NUM_COL = '10';
 
Execution Plan
----------------------------------------------------------
Plan hash value: 621649307

--------------------------------------------------------------------------------------------
| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |              |     1 |   105 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T2           |     1 |   105 |     3   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | SYS_C0030634 |     1 |       |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("NUM_COL"=10)
</pre>
<p>Fun bonus question.  Why is there an implicit datatype conversion of the table&#8217;s column in the first test case (table T1), but instead an implicit datatype conversion of the constant in the second test case (table T2).</p>
]]></content:encoded>
	</item>
</channel>
</rss>
