views:

462

answers:

3

Hi,

i have a table containing 15+ million records in oracle. its sort of a log table which has a created_ts column of type "date" . i have a simple "non-unique" type index on created_ts column.

i have a simple range query :

select * from table1 where created_ts >= ? and created_ts <= ?;

when i run this query from SQLPlus or SQL Developer etc like this :

select * from table1 
where created_ts >= TO_DATE( '2009-11-10 00:00:00', 'YYYY-MM-DD HH24:MI:SS') 
and created_ts <= TO_DATE( '2009-11-10 23:59:59', 'YYYY-MM-DD HH24:MI:SS');

the query returns within 1-2 second max.

but when I run the exact same query in java over JDBC and set the corresponding "?" params using java.sql.Timestamp object . the query takes long time . Analyzing the oracle process it goes for full table scan and doesnt use the index.

the jdbc driver i am using is ojdbc5 11.1.0.7.0

Can any one please help .. how to create the index correctly so that it uses the index.


My problem was resolved when i used "oracle.sql.DATE" objects to set the bind variables instead of "java.sql.timestamp" . The query used the index and executed almost within 1-2 seconds.

Thanks to all who replied and helped.

But its problematic for me as this solution is DB dependent and my app receives DB connection and query as param and load and process data in a generic way. The DB connection can be of any RDBMS like oracle, mysql, etc.

A: 

You should try a hint of the form /*+ USE_INDEX(table_name, index_name) */

My guess is that the optimizer is choosing a full table scan because it sees that as the best option in absence of knowing the bind values.

Alan
Wrong syntax: /*+ INDEX(table index) */ or better still use the newer index specification clause with /*+ INDEX(table (column)) */ or /*+ INDEX(table (table.column)) */
David Aldridge
+2  A: 

The difference may because of bind variables vs. literal values. You are not comparing the same things.

Try this in SQL*Plus:-

explain plan for
select * from table1 where created_ts >= :1 and created_ts <= :2;

set markup html preformat on
set linesize 100
set pagesize 0  
select plan_table_output 
from table(dbms_xplan.display('plan_table',null,'serial'));

This will show you the plan Oracle will pick when using bind variables. In this scenario, Oracle has to make up a plan before you have provided values for your date range. It does not know if you are selecting only a small fraction of the data or all of it. If this has the same plan (full scan?) as your plan from java, at least you konw what is happening.

Then, you could consider:-

  1. Enabling bind peeking (but only after testing this does not cause anything else to go bad)
  2. Carefully binding literal values from java in a way that does not allow SQL injection
  3. Putting a hint in the statement to indicate it should use the index you want it to.
WW
No: http://www.akadia.com/services/ora_bind_variables.html
OMG Ponies
No -> Not usually. Maybe it only runs once a day with certain values and there will only be one hard parse every day? Maybe it's better to live with the hard-parse and allow the CBO to come up with a better plan based on the query?
WW
OMG Ponies
Too much to say for a comment, but see this: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:492078000346228806
WW
Hi I checked the execution plan for bind vars it was using index. But here i guess the problem was that the object passed in java for bind variable was not handled/cast properly into "Date" type value for Oracle DB so it was not using index. see my reply to APC
Ali
+1  A: 

This is classic behaviour for an implicit datatype conversion. Because the database is having to convert the datatype of the column it cannot use any index on that column.

In your case I suspect this is due to your use of java.sql.Timestamp. Would it be possible to use the equivalent type from the Oracle datatypes package, oracle.sql.Timestamp? Obviously that may have some knock-on effects but I think you should at least test it, to see whether that solves your problem.

APC
+1 - I've seen this in the past with Java queries against Oracle date types. If you're licensed to use the dbms_sqltune package and run it against the sql_id (shared pool or AWR repository) you'll see the datatype conversion in the resulting analysis
dpbradley
Hi, 1st of all thanks everyone. but the thing suggested by APC was my guess too. I used oracle.sql.DATE object to set the bind variable values and it worked .. query returned almost instantaneously and when i revert back to java.sql.Timestamp its the same problem that the query goes for full scan and takes too long.
Ali
But this makes my work tough as the app is generic in sense that it can receive connection,query pairs for loading data where connection can be of any DB like oracle, mysql,etc. Is it some problem in ojdbc driver that it doesnt correctly translates the object type "Timestamp" for oracle ? any suggestion on how to fix and keep the process DB-independent will be appreciated Thanks
Ali