对于使用Hibernate的Oracle选择,避免从日期到时间戳的隐式转换

时间:2010-03-17 17:40:47

标签: java oracle hibernate

我正在使用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已经进行了类型映射,那么它是否可以配置为做正确的事情?

更新:问题出现在各种配置中,但这是一个具体的例子:

  • Oracle Enterprise Edition 10.2.0.4.0
  • Oracle JDBC Driver 11.1.0.7.0
  • Hibernate 3.2.7.GA
  • Hibernate的Oracle10gDialect
  • Java 1.6.0_16

2 个答案:

答案 0 :(得分:0)

这可能听起来很激烈,但是当遇到这个问题时,我们最终将所有DATE列转换为数据库中的TIMESTAMP类型。我可以看到,没有任何缺点,如果Hibernate是您的主要应用程序平台,那么您将为自己未来的恶化做好准备。

注意:

  • 可以使用更改列类型 一个简单的“ALTER tableName MODIFY columnName TIMESTAMP(precisionVal)“。

  • 我惊讶地发现索引 在这些栏目上没有必须是 重修。

同样,这只有在你致力于Hibernate时才有意义。

答案 1 :(得分:0)

根据Oracle JDBC FAQ

  

“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),它将完全透明到代码