java - Hibernate 在选择查询中生成过多的连接

标签 java mysql spring hibernate jpa

在使用 Hibernate 和 JPA 的 Spring MVC 应用程序中。 Hibernate 使用 78 个连接创建了一个过于复杂的查询,而实际上只需要少量连接。我正在使用 InhertanceType.JOINED

为了简化问题和实验,我在相关实体中注释掉了很多属性,并且我还将父类的代码剪切并粘贴到子类中以减少继承量。这将联接中应包含的表数减少到 8 个。但是,当我在其中一个实体上尝试 EntityManager.persist() 时,hibernate 会生成不应包含的联接。如何隔离我的代码中的问题?

您可以查看应包含在联接中的 8 到 12 个类的类图 by clicking on this link .这是一个 JPEG 文件,您可以通过单击它在浏览器中放大。连接中可能只包含 8 到 12 个类,但 Hibernate 在连接中包含额外的 12 个不相关的表,这是完全没有必要的。为什么?

以下是不应包含在连接中的实体列表:

PQ
QTY
ANY_
SXCMPQ
IVLPQ
BXITIVLPQ
HXITPQ
PPDPQ
SXCMPPDPQ
IVLPPDPQ
IVXBPPDPQ
IVXBPQ

这是应该加入连接的实体列表:

Person
LivingEntity
rimEntity
Role
CD
TS
II
EN

这是引发问题的 DAO 方法:

@Override
    public void saveRIMPerson(Person myperson) throws DataAccessException{
    if (myperson.getHppid() == null) {this.em.persist(myperson);}//EXCESSIVE SQL CREATED HERE
    else {this.em.merge(myperson);}
}  

下面是生成的 SQL 中的连接:

Hibernate: select `lots of properties`
 from
 rim_entity person0_ left outer join CD cd1_ on person0_.classCode_HJID=cd1_.HJID
 left outer join TS ivlts2_ on cd1_.VALID_TIME_HXITCE_HJID=ivlts2_.HJID
 left outer join II ids3_ on person0_.hppid=ids3_.ids_entity_HJID
 left outer join CD cd4_ on person0_.administrativeGenderCode_HJID=cd4_.HJID
 left outer join TS ts5_ on person0_.birthTime_HJID=ts5_.HJID
 left outer join PQ pq6_ on ts5_.STANDARD_DEVIATION_PPDTS_HJID=pq6_.HJID
 left outer join QTY pq6_1_ on pq6_.HJID=pq6_1_.HJID
 left outer join ANY_ pq6_2_ on pq6_.HJID=pq6_2_.HJID
 left outer join SXCMPQ pq6_3_ on pq6_.HJID=pq6_3_.HJID
 left outer join IVLPQ pq6_4_ on pq6_.HJID=pq6_4_.HJID
 left outer join BXITIVLPQ pq6_5_ on pq6_.HJID=pq6_5_.HJID
 left outer join HXITPQ pq6_6_ on pq6_.HJID=pq6_6_.HJID
 left outer join PPDPQ pq6_7_ on pq6_.HJID=pq6_7_.HJID
 left outer join SXCMPPDPQ pq6_8_ on pq6_.HJID=pq6_8_.HJID
 left outer join IVLPPDPQ pq6_9_ on pq6_.HJID=pq6_9_.HJID
 left outer join IVXBPPDPQ pq6_10_ on pq6_.HJID=pq6_10_.HJID
 left outer join IVXBPQ pq6_11_ on pq6_.HJID=pq6_11_.HJID
 left outer join CD eivlevent7_ on ts5_.EVENT_EIVLPPDTS_HJID=eivlevent7_.HJID
 left outer join IVLPPDPQ ivlppdpq8_ on ts5_.OFFSET__EIVLPPDTS_HJID=ivlppdpq8_.HJID
 left outer join SXCMPPDPQ ivlppdpq8_1_ on ivlppdpq8_.HJID=ivlppdpq8_1_.HJID
 left outer join PPDPQ ivlppdpq8_2_ on ivlppdpq8_.HJID=ivlppdpq8_2_.HJID
 left outer join PQ ivlppdpq8_3_ on ivlppdpq8_.HJID=ivlppdpq8_3_.HJID
 left outer join QTY ivlppdpq8_4_ on ivlppdpq8_.HJID=ivlppdpq8_4_.HJID
 left outer join ANY_ ivlppdpq8_5_ on ivlppdpq8_.HJID=ivlppdpq8_5_.HJID
 left outer join CD eivlevent9_ on ts5_.EVENT_EIVLTS_HJID=eivlevent9_.HJID
 left outer join IVLPQ ivlpq10_ on ts5_.OFFSET__EIVLTS_HJID=ivlpq10_.HJID
 left outer join SXCMPQ ivlpq10_1_ on ivlpq10_.HJID=ivlpq10_1_.HJID
 left outer join PQ ivlpq10_2_ on ivlpq10_.HJID=ivlpq10_2_.HJID
 left outer join QTY ivlpq10_3_ on ivlpq10_.HJID=ivlpq10_3_.HJID
 left outer join ANY_ ivlpq10_4_ on ivlpq10_.HJID=ivlpq10_4_.HJID
 left outer join BXITIVLPQ ivlpq10_5_ on ivlpq10_.HJID=ivlpq10_5_.HJID
 left outer join TS ppdts11_ on ts5_.CENTER_IVLPPDTS_HJID=ppdts11_.HJID
 left outer join TS ivxbppdts12_ on ts5_.HIGH_IVLPPDTS_HJID=ivxbppdts12_.HJID
 left outer join TS ivxbppdts13_ on ts5_.LOW_IVLPPDTS_HJID=ivxbppdts13_.HJID
 left outer join PPDPQ ppdpq14_ on ts5_.WIDTH_IVLPPDTS_HJID=ppdpq14_.HJID
 left outer join PQ ppdpq14_1_ on ppdpq14_.HJID=ppdpq14_1_.HJID
 left outer join QTY ppdpq14_2_ on ppdpq14_.HJID=ppdpq14_2_.HJID
 left outer join ANY_ ppdpq14_3_ on ppdpq14_.HJID=ppdpq14_3_.HJID
 left outer join SXCMPPDPQ ppdpq14_4_ on ppdpq14_.HJID=ppdpq14_4_.HJID
 left outer join IVLPPDPQ ppdpq14_5_ on ppdpq14_.HJID=ppdpq14_5_.HJID
 left outer join IVXBPPDPQ ppdpq14_6_ on ppdpq14_.HJID=ppdpq14_6_.HJID
 left outer join TS ts15_ on ts5_.CENTER_IVLTS_HJID=ts15_.HJID
 left outer join TS ivxbts16_ on ts5_.HIGH_IVLTS_HJID=ivxbts16_.HJID
 left outer join TS ivxbts17_ on ts5_.LOW_IVLTS_HJID=ivxbts17_.HJID
 left outer join PQ pq18_ on ts5_.WIDTH_IVLTS_HJID=pq18_.HJID
 left outer join QTY pq18_1_ on pq18_.HJID=pq18_1_.HJID
 left outer join ANY_ pq18_2_ on pq18_.HJID=pq18_2_.HJID
 left outer join SXCMPQ pq18_3_ on pq18_.HJID=pq18_3_.HJID
 left outer join IVLPQ pq18_4_ on pq18_.HJID=pq18_4_.HJID
 left outer join BXITIVLPQ pq18_5_ on pq18_.HJID=pq18_5_.HJID
 left outer join HXITPQ pq18_6_ on pq18_.HJID=pq18_6_.HJID
 left outer join PPDPQ pq18_7_ on pq18_.HJID=pq18_7_.HJID
 left outer join SXCMPPDPQ pq18_8_ on pq18_.HJID=pq18_8_.HJID
 left outer join IVLPPDPQ pq18_9_ on pq18_.HJID=pq18_9_.HJID
 left outer join IVXBPPDPQ pq18_10_ on pq18_.HJID=pq18_10_.HJID
 left outer join IVXBPQ pq18_11_ on pq18_.HJID=pq18_11_.HJID
 left outer join PPDPQ ppdpq19_ on ts5_.PERIOD_PIVLPPDTS_HJID=ppdpq19_.HJID
 left outer join PQ ppdpq19_1_ on ppdpq19_.HJID=ppdpq19_1_.HJID
 left outer join QTY ppdpq19_2_ on ppdpq19_.HJID=ppdpq19_2_.HJID
 left outer join ANY_ ppdpq19_3_ on ppdpq19_.HJID=ppdpq19_3_.HJID
 left outer join SXCMPPDPQ ppdpq19_4_ on ppdpq19_.HJID=ppdpq19_4_.HJID
 left outer join IVLPPDPQ ppdpq19_5_ on ppdpq19_.HJID=ppdpq19_5_.HJID
 left outer join IVXBPPDPQ ppdpq19_6_ on ppdpq19_.HJID=ppdpq19_6_.HJID
 left outer join TS ivlppdts20_ on ts5_.PHASE_PIVLPPDTS_HJID=ivlppdts20_.HJID
 left outer join PQ pq21_ on ts5_.PERIOD_PIVLTS_HJID=pq21_.HJID
 left outer join QTY pq21_1_ on pq21_.HJID=pq21_1_.HJID
 left outer join ANY_ pq21_2_ on pq21_.HJID=pq21_2_.HJID
 left outer join SXCMPQ pq21_3_ on pq21_.HJID=pq21_3_.HJID
 left outer join IVLPQ pq21_4_ on pq21_.HJID=pq21_4_.HJID
 left outer join BXITIVLPQ pq21_5_ on pq21_.HJID=pq21_5_.HJID
 left outer join HXITPQ pq21_6_ on pq21_.HJID=pq21_6_.HJID
 left outer join PPDPQ pq21_7_ on pq21_.HJID=pq21_7_.HJID
 left outer join SXCMPPDPQ pq21_8_ on pq21_.HJID=pq21_8_.HJID
 left outer join IVLPPDPQ pq21_9_ on pq21_.HJID=pq21_9_.HJID
 left outer join IVXBPPDPQ pq21_10_ on pq21_.HJID=pq21_10_.HJID
 left outer join IVXBPQ pq21_11_ on pq21_.HJID=pq21_11_.HJID
 left outer join TS ivlts22_ on ts5_.PHASE_PIVLTS_HJID=ivlts22_.HJID
 where person0_.hppid=? and person0_.DTYPE='rimPerson'

可以通过单击 on this link 找到 Person 实体的代码.可以通过单击 on this link 找到所有其他实体的代码。 .

我唯一能想到的是,底层的 MySQL 数据库在每个表上都有很多连接,但是数据库是使用这些和其他类作为输入从 hbm2ddl 生成的。我的代码有问题吗?或者我还应该去哪里看?

最佳答案

虽然从 OOP 的角度来看,这种相互连接的设计是有效的,但您必须记住,在后台您正在处理关系数据库,因此过多的继承会损害性能。

解释联接

您当前的查询根实体是 Person,所提供的图表具有误导性,因为它没有说明 Person 是一个 LivingSubject,而 LivingSubject 是一个 RimEmtity。

rimEntity.classCode 被标记为惰性,但我看到 Hibernate 尝试改为外连接。这不应该发生,因为第二个选择应该加载它,所以我怀疑代码和错误不同步,因为在 CD 类中也找不到这个关联:

left outer join TS ivlts2_ on cd1_.VALID_TIME_HXITCE_HJID=ivlts2_.HJID

让我们来看另一个@ManyToOne,LivingSubject.birthTime

left outer join TS ts5_ on person0_.birthTime_HJID=ts5_.HJID

所以所有这些都与整个 Person 类层次结构的@ManyToOne 关联有关。

一种可能的“解决方案”:

尝试设置这个属性:

hibernate.max_fetch_depth=0

这将禁用外部连接,然后 Hibernate 将使用额外的选择,但这可能会进一步损害性能。

使用 auto-generated code and hbmddl是一个糟糕的设计决定。您的数据库模式应该由增量更新脚本生成,您的 Hibernate 映射应该将数据库表映射到域模型类。

拥有如此多的关系会严重影响性能,因此没有解决问题的 Elixir 。

您应该首先设计数据库表和查询​​,然后决定什么是最适合您的应用程序需求的域模型。

关于java - Hibernate 在选择查询中生成过多的连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26769989/

相关文章:

java - 如何在迭代时在常数时间内修改 Java 链表中的元素?

java - Zkoss - 在浏览器的新标签页中打开 url

java - 如何在 spring Controller 中处理数据库特定异常

java - 使用嵌套 if 语句在 while 循环中循环出现问题

java - 如何使用mysql查询返回计数?

php - 为什么我不能在 MySQL 升级后向列中插入 NULL 值?

mysql - SQL 在表中查找位置

java - 在 Soap Security Header (Spring WS) 中设置自定义标签

java - 我收到异常 BindingResult 和 bean 名称 'studentRegistration' 的普通目标对象都可用作 spring 中的请求属性

java - MVC 中的 Spring Security 配置