我有一个在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不是数据库中的真实表)。例如,要获取表单的所有子项,休眠会从表Form
,Category
,Group
,Question
创建多重联合以表示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
的内容来过滤“大”联合查询,只检索类别和问题中的真实子项,而不是所有这些,从而避免了性能问题。但是当child 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的所有子项?
答案 0 :(得分:1)
ManyToOne
注释默认为EAGER
,我认为您并不真正需要直接加载的对象的父级(通过主键),对吗?
您可以像这样更改关联:
@ManyToOne(fetch = FetchType.LAZY)
private TreeObject parent;
这至少应该删除与工会的最后一次加入。
但由于模型的性质(它是递归),您将无法在没有本机查询的情况下选择整个对象图,因为JPA根本不支持它。即使是原生查询也可能不是最佳解决方案,我认为您应该考虑使用文档存储,这样您就可以在一次操作中存储/加载整个图形。