我正在使用Hibernate 3.2.7.GA条件查询从Oracle Enterprise Edition 10.2.0.4.0数据库中选择行,并按时间戳字段进行过滤。相关字段在Java中为java.util.Date
,在Oracle中为DATE
。
It turns out该字段被映射到java.sql.Timestamp
,并且Oracle在将所有行转换为TIMESTAMP
之前与传入的值bypassing the index进行比较,从而破坏了性能。< / p>
一种解决方案是使用Hibernate的sqlRestriction()
和Oracle的TO_DATE
函数。这将修复性能,但需要重写应用程序代码(大量查询)。
那么有更优雅的解决方案吗?既然Hibernate已经进行了类型映射,那么它是否可以配置为做正确的事情?
更新:问题出现在各种配置中,但这是一个具体的例子:
答案 0 :(得分:0)
这可能听起来很激烈,但是当遇到这个问题时,我们最终将所有DATE列转换为数据库中的TIMESTAMP类型。我可以看到,没有任何缺点,如果Hibernate是您的主要应用程序平台,那么您将为自己未来的恶化做好准备。
注意:
可以使用更改列类型 一个简单的“ALTER tableName MODIFY columnName TIMESTAMP(precisionVal)“。
我惊讶地发现索引 在这些栏目上没有必须是 重修。
同样,这只有在你致力于Hibernate时才有意义。
答案 1 :(得分:0)
“11.1驱动程序默认情况下,在从数据库读取时将SQL DATE转换为时间戳”
所以这是一种预期的行为。
对我而言,这意味着来自DATE
列的实际值将转换为java.sql.Timestamp
,而不是java.util.Date
的绑定变量转换为java.sql.Timestamp
。
EXPLAIN PLAN
输出有助于识别问题。此外,Oracle跟踪可以准确地告诉您在查询中为绑定变量分配了什么类型。
如果真的发生这可能是Oracle的错误。
你可以这样解决:
在DATE
列上创建一个FBI(Function Based Index),并将其投放到TIMESTAMP
。例如:
CREATE INDEX tab_idx ON tab (CAST(date_col AS TIMESTAMP)) COMPUTE STATISTICS;
创建包含相同CAST
表达式的视图。如果需要,可以保留相同的列名称:
CREATE VIEW v AS
SELECT CAST(date_col AS TIMESTAMP) AS date_col, col_1, ... FROM tab;
使用View而不是Table(无论如何,这通常是一个好主意,例如,如果您已经在使用View,则根本不需要更改代码)。当java.sql.Timestamp
变量与date_col
条件中的WHERE
一起使用时(如果选择性足够),将使用索引。
如果您发现为什么有java.sql.Timestamp
(或Oracle修复了潜在的错误),您可以随时返回只更改视图(并删除FBI),它将完全透明到代码