У меня здесь похожая проблема:
Незначительная разница в плане выполнения с Oracle при использовании jdbc Timestamp или Date
В моем примере это сводится к тому факту, что при использовании метки времени JDBC, INTERNAL_FUNCTION
применяется к столбцу фильтра, а не к переменной bind. Таким образом, индекс больше нельзя использовать для RANGE SCANS
или UNIQUE SCANS
:
// 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 < ?");
Эти две привязки приводят к совершенно разному поведению (чтобы исключить проблемы просмотра переменных привязки, я фактически ввел два жестких анализа):
// 1. with timestamps
stmt.setTimestamp(1, start);
stmt.setTimestamp(2, end);
// 2. with dates
stmt.setDate(1, start);
stmt.setDate(2, end);
1) С отметками времени я получаю INDEX FULL SCAN
и, таким образом, предикат фильтра
--------------------------------------------------------------
| 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) С датами я получаю намного лучше INDEX RANGE SCAN
и предикат доступа
--------------------------------------------------------------
| 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)
Решение этой проблемы внутри сторонних API
Кстати, эту проблему также можно решить в сторонних API, например, в Hibernate:
или в jOOQ: