Why is Oracle so slow when I pass a java.sql.Timestamp for a DATE column?

前端 未结 4 1878
梦如初夏
梦如初夏 2020-12-15 01:15

I have a table with a DATE column with time (as usual in Oracle since there isn\'t a TIME type). When I query that column from JDBC, I have two opt

4条回答
  •  轮回少年
    2020-12-15 02:09

    I have a similar problem here:

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

    In my example it essentially comes down to the fact that when using JDBC Timestamp, an INTERNAL_FUNCTION is applied to the filter column, not the bind variable. Thus, the index cannot be used for RANGE SCANS or UNIQUE SCANS anymore:

    // execute_at is of type DATE.
    PreparedStatement stmt = connection.prepareStatement(
        "SELECT /*+ index(my_table my_index) */ * " + 
        "FROM my_table " +
        "WHERE execute_at > ? AND execute_at < ?");
    

    These two bindings result in entirely different behaviour (to exclude bind variable peeking issues, I actually enforced two hard-parses):

    // 1. with timestamps
    stmt.setTimestamp(1, start);
    stmt.setTimestamp(2, end);
    
    // 2. with dates
    stmt.setDate(1, start);
    stmt.setDate(2, end);
    

    1) With timestamps, I get an INDEX FULL SCAN and thus a filter predicate

    --------------------------------------------------------------
    | Id  | Operation                    | Name                  |
    --------------------------------------------------------------
    |   0 | SELECT STATEMENT             |                       |
    |*  1 |  FILTER                      |                       |
    |   2 |   TABLE ACCESS BY INDEX ROWID| my_table              |
    |*  3 |    INDEX FULL SCAN           | my_index              |
    --------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       1 - filter(:1<:2)"
       3 - filter((INTERNAL_FUNCTION(""EXECUTE_AT"")>:1 AND 
                   INTERNAL_FUNCTION(""EXECUTE_AT"")<:2))
    

    2) With dates, I get the much better INDEX RANGE SCAN and an access predicate

    --------------------------------------------------------------
    | Id  | Operation                    | Name                  |
    --------------------------------------------------------------
    |   0 | SELECT STATEMENT             |                       |
    |*  1 |  FILTER                      |                       |
    |   2 |   TABLE ACCESS BY INDEX ROWID| my_table              |
    |*  3 |    INDEX RANGE SCAN          | my_index              |
    --------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
       1 - filter(:1<:2)"
       3 - access(""EXECUTE_AT"">:1 AND ""EXECUTE_AT""<:2)
    

    Solving this problem inside third-party APIs

    For the record, this problem can also be solved within third-party APIs for instance in Hibernate:

    • http://blog.jooq.org/2014/12/29/leaky-abstractions-or-how-to-bind-oracle-date-correctly-with-hibernate/

    Or in jOOQ:

    • http://blog.jooq.org/2014/12/22/are-you-binding-your-oracle-dates-correctly-i-bet-you-arent/

提交回复
热议问题