Non-negligible execution plan difference with Oracle when using jdbc Timestamp or Date

允我心安 提交于 2019-11-28 20:47:39

So the thing is, Oracle timestamps and Oracle dates are two different datatypes. In order to compare a timestamp to a date Oracle has to run a conversion - that INTERNAL_FUNCTION(). The interesting design decision is that Oracle converts the table column rather than the passed value, which means the query no longer uses the index.

I have been able to reproduce your scenario in SQL*Plus, so it's not a problem with using java.sql.Timestamp. Casting the passed timestamps to dates does resolve the problem...

SQL> explain plan for
  2      select * from test1
  3      where d1 > cast(to_timestamp('01-MAY-2011 00:00:00.000', 'DD-MON-YYYY Hh24:MI:SS.FF') as date)
  4       and d2 > cast(to_timestamp('01-JUN-2011 23:59:59.999', 'DD-MON-YYYY Hh24:MI:SS.FF') as date)
  5  /

Explained.

SQL> select * from table(dbms_xplan.display)
  2  /

PLAN_TABLE_OUTPUT
-----------------------------------------------------------
Plan hash value: 1531258174

-------------------------------------------------------------------------------------
| Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |       |    25 |   500 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TEST1 |    25 |   500 |     3   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | T1_I  |     1 |       |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------    
   2 - access("D1">CAST(TO_TIMESTAMP('01-MAY-2011 00:00:00.000','DD-MON-YYYY
              Hh24:MI:SS.FF') AS date) AND "D2">CAST(TO_TIMESTAMP('01-JUN-2011
              23:59:59.999','DD-MON-YYYY Hh24:MI:SS.FF') AS date) AND "D1" IS NOT NULL)
       filter("D2">CAST(TO_TIMESTAMP('01-JUN-2011 23:59:59.999','DD-MON-YYYY
              Hh24:MI:SS.FF') AS date))

18 rows selected.

SQL>

But I don't think that helps you any: it would be easier to just pass dates instead.


Interestingly, building a function-based index casting the date columns to timestamps doesn't help. The INTERNAL_FUNCTION() call isn't recognised as a CAST() and the index is ignored. Trying to build an index using INTERNAL_FUNCTION() hurls an ORA-00904.

Lukas Eder

While APC's answer already sufficiently explains why this is happening, the following blog posts are interesting in case you're trying to solve this problem with JPA and Hibernate:

Or with JDBC or jOOQ:

In particular, a possible solution is to simply pass oracle.sql.DATE instead of any java.sql type to the PreparedStatement

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!