gpt4 book ai didi

java - 使用 TABLE_PER_CLASS 导致查询中有多个表时,如何提高性能?

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:52:19 24 4
gpt4 key购买 nike

我在 hibernate 中定义了一个树结构。我有一个名为 TreeObject 的抽象元素。一个树对象可以有多个子对象,而只有一个父对象。

我也有这个类的一些实现:表单、类别、问题组和问题。它们都继承自 TreeObject。

这个想法是一个表单可以有子类别和问题。类别可以有子组和问题,组可以有其他组和问题。

然后我将 TreeObject 定义为:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class TreeObject{

@ManyToOne
private TreeObject parent;

@OneToMany(mappedBy = "parent")
private List<TreeObject> children;

[...]
}

然后,其他对象就很简单了。例如,表单元素是:

@Entity
public class Form extends TreeObject {
[...]
}

和其他元素类似,除了这个问题的一些不相关的代码。

问题出在我想检索元素的子元素时(因为 TreeObject 不是数据库中的真实表)。例如,为了获取表单的所有子项,hibernates 从表 FormCategoryGroupQuestion 用于表示 TreeObject 表等效项并选择子项。当数据库有多个元素(但不是那么多)时,由于生成了多个联合,获取子项可能需要大约 0.5 秒。然后,当我拥有大量数据时,该查询将遇到很大的性能问题。

例如,获取表单的查询示例是:

select form0_.ID as ID1_7_0_, form0_.createdBy as createdB3_7_0_,  form0_.name as name2_12_0_, form0_.parent_ID as parent_I5_12_0_, children1_.parent_ID as parent_I5_7_1_, children1_.ID as ID1_12_1_, children1_.ID as ID1_7_2_, children1_.createdBy as createdB3_7_2_, children1_.name as name2_12_2_, children1_.parent_ID as parent_I5_12_2_, children1_.version as version2_2_2_, children1_.clazz_ as clazz_2_, questionva2_.BaseQuestionWithValue_ID as BaseQues1_7_3_, questionva2_.questionValues as question2_38_3_, treeobject3_.ID as ID1_7_4_, treeobject3_.comparationId as comparat2_7_4_, treeobject3_.name as name2_12_4_, treeobject3_.parent_ID as parent_I5_12_4_, treeobject3_.clazz_ as clazz_4_ from form form0_ left outer join 
( select ID, name, parent_ID, 10 as clazz_ from questions
union select ID, name, parent_ID, 24 as clazz_ from group
union select ID, name, parent_ID, 32 as clazz_ from category
union select ID, name, parent_ID, 26 as clazz_ from form )
children1_ on form0_.ID=children1_.parent_ID left outer join
question_with_values questionva2_ on children1_.ID=questionva2_.BaseQuestionWithValue_ID left outer join
( select ID, name, parent_ID, 10 as clazz_ from questions
union select ID, name, parent_ID, 24 as clazz_ from group
union select ID, name, originalReference, parent_ID, 32 as clazz_ fromcategory
union select ID, comparationId, name, parent_ID, 26 as clazz_ from form )
treeobject3_ on form0_.parent_ID=treeobject3_.ID where form0_.ID=344820 order by children1_.sortSeq asc;

(注意:我删除了几列,以便更容易理解代码)

现在我已经使用@BatchSize 来提高性能,并且应用程序的总体性能更好,但仍然不是真正的解决方案。

我的想法是使用类似 @WhereJoinTable 的东西来过滤“大”联合查询,并且只从 Category 和 Questions 中检索真正的子项而不是全部,从而避免性能问题。但是由于 children 参数由 parent 映射,我不知道如何实现这一点。

    @ManyToOne
@JoinColumn(name="parent_ID")
@WhereJoinTable(clause=" ???? ")
private TreeObject parent;

也许使用 Hibernate 的 @Filter 选项:

    @ManyToOne
@JoinColumn(name="parent_ID")
@Filter(name="parentGroup",condition=" ???? ")
private TreeObject parent;

当然,另一种解决方案是将 InheritanceType.TABLE_PER_CLASS 更改为只有一个大表,因此 union 不会出现在查询中。但是数据库会很难读,我想避免它。

问题是:是否存在任何方法来提高 Hibernate 检索 TreeObject 的所有子项的性能?

最佳答案

ManyToOne 注释默认是 EAGER 并且我认为您并不真的需要直接加载的对象的父级(通过主键),对吧?

您可以这样更改关联:

@ManyToOne(fetch = FetchType.LAZY)
private TreeObject parent;

这至少应该删除与联合的最后一个连接。

但是由于模型的性质(它是递归),如果没有 native 查询,您将永远无法选择整个对象图,因为 JPA 根本不支持它。即使是 native 查询也可能不是最佳解决方案,我认为您应该考虑使用文档存储,它使您能够在一次操作中存储/加载整个图形。

关于java - 使用 TABLE_PER_CLASS 导致查询中有多个表时,如何提高性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39894671/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com