我正在分析Oracle执行计划,并发现了一个令人惊讶的事实。看看这个查询。提示只是为了显示我有一个索引,我希望Oracle将它用于范围扫描:
// 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)
现在我的例子只是一个例子。真正的查询要复杂得多,必须具备 RANGE SCANS
要么 UNIQUE SCANS
(取决于谓词)而不是 FULL SCANS
。
我有什么误解吗?有人能指出我最好的解决方案/做法吗?因为在Java世界中,我认为 java.sql.Timestamp
更合适,但我们的大多数专栏都是Oracle的 DATE
类型。我们使用的是Java 6和Oracle 11g