猿问

如何使用 Hibernate 避免从 VARCHAR 到 VARCHAR2 的隐式类型转换?

一些同事提出了一个问题,他们发现查询执行时间很慢,并且发现由于隐式类型转换而未使用索引。

kgb_uuid该表有一个用于存储 UUID 的属性。该列被定义为VARCHAR2并具有一个索引,用于通过 UUID 搜索行。

实体中的相关字段定义为String。根据 Hibernate 文档,Hibernate 应该将此字符串转换为VARCHAR2Oracle 数据库,因此应该使用索引。

但事实并非如此,如日志所示:

[9/2/19 11:56:07:610 CEST] 00000177 SystemOut O
2019-09-02T11:56:07,610 TRACE [ebContainer : 3] ibebcTraceInterceptor;log;;41 - 类 [MyDAO] 中的入口方法 [checkEindeutigeUUID]带参数 (MyEntity@b14745f9)

[9/2/19 11:56:07:688 CEST] 00000177 SQL Z org.hibernate.engine.jdbc.spi.SqlStatementLogger logStatement 选择 count(mytab0_.KGB_NR) as col_0_0_ from MYENTITYTABLE mytab_ where mytab_.KGB_UUID=?和 mytab_.EKN_NR=?

[9/2/19 11:56:07:688 CEST] 00000177 BasicBinder Z org.hibernate.type.descriptor.sql.BasicBinder 绑定参数 [1] 作为 [VARCHAR] - 795BF3B98D879358E0531C03A90ABF0A [9/2/19 11:56 :07:688 CEST] 00000177 BasicBinder Z org.hibernate.type.descriptor.sql.BasicBinder 绑定绑定参数 [2] 作为 [BIGINT] - 1

正如所见,字符串值被绑定为VARCHARnot as VARCHAR2,导致数据库进行隐式类型转换并且不使用索引,如 OEM 中所示(这是来自 OEM 的原始德语消息):

执行计划的行 ID 3 中使用的谓词 SYS_OP_C2C("mytab_"."KGB_UUID")=:B1 包含索引列“KGB_UUID”上的隐式数据类型转换。这种隐式数据类型转换会阻止优化器有效地使用表“MYENTITYTABLE”上的索引。

它表示使用了谓词SYS_OP_C2C("mytab_"."KGB_UUID")=:B1,并且它包含索引基列的隐式属性类型的对话KGB_UUID,并且该隐式类型的对话阻止优化器有效地使用表的索引MYENTITYTABLE

我们已经解决了在表上使用功能索引的问题,但我们仍然想知道为什么 Hibernate 提供了一种显然不是VARCHAR2.

系统:

  • Hibernate 4.2.21 与 Hibernate Dialect Oracle10g(根据文档最多兼容 12 个)

  • Oracle 12.2(现在不完全是,我认为是12.2,但也许只是12.1)

Hibernate 版本无法升级,因为它是可与 JPA 2.0 一起使用的最后一个版本,JPA 2.0 是 Websphere Process Server 8.5 支持的 JavaEE 6 的一部分。

(简称)实体

@Entity

@Table(name = "MYENTITYTABLE")

public class MyEntity implements Serializable {

  private static final long serialVersionUID = 1L;


  @Id

  // out commented the sequence generator 

  @Column(name="KGB_NR")

  private long kgbNr;


  @Column(name="KGB_UUID")

  private String kgbUuid; // <<== DEFINED AS STRING!


  //bi-directional many-to-one association to Ekistnutzer

  @ManyToOne

  @JoinColumn(name="EKN_NR")

  private EkistnutzerEntity ekistnutzer;


  // Other attributes not related in problem


MMTTMM
浏览 123回答 1
1回答

青春有我

最简单的方法是扩展默认值StringType并覆盖sqlType属性,并通过注释向实体属性提供新的 Hibernate 类型@Type。该映射很可能VARCHAR2是通过 Oracle Hibernate Dialect 实现的,因此您不应该覆盖默认的 Dialect 映射,因为可能存在正确使用VARCHAR2.因此,自定义 Hibernate 类型为您提供了控制权,并允许您仅将其用于列VARCHAR。
随时随地看视频慕课网APP

相关分类

Java
我要回答