Oracle optimizer is pure voodoo
A problem we ran into at work today..
A table with mucho data and a date column. The date column has an index on it and its type is just pure old date. A query using jdbc and java.sql.Timestamp type on a prepared statement generates a full table scan.. and the associated slllloowwwwwnnnessssssss.
Identical query using java.sql.Date on a prepared statement or to_date(String, format) in the SQL uses the index.
Am I missing some obvious Oracle clue here? Cause google isn't helping!
Edit: I realize we can hint to Oracle which indexes to use, but it would be nice to have a more general solution.
Comments
My Oracle is a few years old, but here's what I'd guess:
The use of Timestamp is causing the JDBC layer (probably) to generate SQL with some combination of function calls that causes Oracle to skip the index. It used to have problems even with TO_DATE in the WHERE clause, but this could just be a brain-dead implementation in the JDBC driver.
There should be a way to capture the SQL that is actually being executed against the DB; can you see if you can grab that and compare the two versions?
Posted by: Pete Puma | May 25, 2006 09:13 PM
Yah, we looked at the actual SQL being executed, the queries are identical :(
Posted by: kasia | May 25, 2006 09:14 PM
It might have something to do with the extra resolution provided by java.sql.Timestamp (nanoseconds) vs. java.sql.Date (milliseconds) vs Oracle DATE data type (seconds).
I know you mentioned that the SQL was identical, but you can try taking a look at some of Oracle's v$ performance views such as v$sql to find out what SQL has been executed. Once you get the SQL, you can run an explain plan on it even without the bind variables. If there really is only one query matching yours, it sounds like it could be a problem with the JDBC driver.
select ses.sid, ses.username, sql.sql_text, sql.hash_value, sql.executions, sql.parse_calls, sql.disk_reads, sql.buffer_gets, sql.last_load_time from v$sql sql, v$session ses where sql.hash_value = ses.sql_hash_value order by sql.last_load_time desc;Nice site by the way.
Posted by: David | May 25, 2006 11:15 PM
Oracle has some bizarre behavior when it comes to Dates vs. Timestamps. You can only do time operations if you cast a date to a timestamp. And if you call rs.getObject() on what is supposed to be a timestamp, it returns oracle.sql.TIMESTAMP, which doesn't even implement java.sql.Timestamp. Urgh.
So what I think is that the date comparison feature is what is allowing the index to be used.
This URL has all the info:
http://www.databasejournal.com/features/oracle/article.php/2234501
Posted by: Will Sargent | May 26, 2006 02:34 AM
We have also had sporadic problems with timestamp. The link Will pointed you to is a good one, Mr. Koopman has a way of explaining things missing in many "Expert" posts. Opinion: the optimizer as it exists today is terrific but extremely complex...it is what it is, and does exactly what it is supposed to do. 95% of the time, it makes the right decision. Sometimes, you have to tell it what to do with hints or change your code a bit.
One problem results from various versions of Oracle JDBC drivers around which behave differently when interpreting a DATE or TIMESTAMP. We find that the best practice is to have DATE really just use the date portion, and TIMESTAMP use both the date and time portion.
Posted by: Mike Larkin | June 6, 2006 09:06 AM