多个 children 的 Hibernate N+1 问题
Hibernate N+1 issue for Multiple children
我有一个实体 class,它有多个 children 与 oneToMany
关联:
public class A{
private Long id;
private String name;
@OneToMany(mappedBy = "A", fetch = FetchType.LAZY, cascade = CascadeType.ALL,
orphanRemoval = true)
private List<B>bList= new ArrayList<>();
@OneToMany(mappedBy = "A", fetch = FetchType.LAZY, cascade = CascadeType.ALL,
orphanRemoval = true)
private List<C>cList= new ArrayList<>();
@OneToMany(mappedBy = "A", fetch = FetchType.LAZY, cascade = CascadeType.ALL,
orphanRemoval = true)
private List<D>dList= new ArrayList<>();
//getters and setters
}
对于 B、C 和 D,我设置了 ManyToOne
。一句话,他们是bi-directional关系
现在,如果我通过 ID 获取 A,我会看到很多查询被触发,结果是 N+1
问题。为了解决这个问题,我将 @Fetch(FetchMode.SUBSELECT)
添加到上面的所有 oneToMany
关系中,这会导致触发更少的查询。
我的问题是:
可以使用 @Fetch(FetchMode.SUBSELECT)
还是我可以进一步优化它?
如果我想通过调用 findAll() 方法获取所有“As”怎么办?多个 children 的语法应该是什么?喜欢
"select a from A a join fetch a.b then ??"
列表< A > findAll()
Now, If I fetch A by id, I see a lot of queries get fired which turns out to be N+1 problem. To solve this, I added @Fetch(FetchMode.SUBSELECT) to all of the oneToMany relationships above which cause less queries to be fired.
您并不是说 how/when 这些查询已被触发,因此问题的可能原因是您从 HTTP 端点返回实体,然后将其序列化。使用 @Fetch(FetchMode.SUBSELECT)
是“提高”性能的一种方法,但只有在用于获取 A
的基本查询很简单的情况下才能很好地工作。如果它变得太复杂(分页、复杂谓词等),您应该坚持使用默认值 SELECT
,而是通过 @BatchSize( size = 32 )
注释配置适当的批处理大小。批处理大小的一个好的值是您希望返回的 A
个实例的数量,这样每个集合只执行一个查询。如果您允许最大页面大小为例如50,你设置成50就完美了
List< A > findAll()
如果您关心性能和可用性,请不要这样做。允许返回所有元素几乎没有意义,因为任何用户一次都不能处理超过 20 个元素。如前所述,始终对页面大小设置某种上限,以防止可能导致性能问题的误用。
我有一个实体 class,它有多个 children 与 oneToMany
关联:
public class A{
private Long id;
private String name;
@OneToMany(mappedBy = "A", fetch = FetchType.LAZY, cascade = CascadeType.ALL,
orphanRemoval = true)
private List<B>bList= new ArrayList<>();
@OneToMany(mappedBy = "A", fetch = FetchType.LAZY, cascade = CascadeType.ALL,
orphanRemoval = true)
private List<C>cList= new ArrayList<>();
@OneToMany(mappedBy = "A", fetch = FetchType.LAZY, cascade = CascadeType.ALL,
orphanRemoval = true)
private List<D>dList= new ArrayList<>();
//getters and setters
}
对于 B、C 和 D,我设置了 ManyToOne
。一句话,他们是bi-directional关系
现在,如果我通过 ID 获取 A,我会看到很多查询被触发,结果是 N+1
问题。为了解决这个问题,我将 @Fetch(FetchMode.SUBSELECT)
添加到上面的所有 oneToMany
关系中,这会导致触发更少的查询。
我的问题是:
可以使用
@Fetch(FetchMode.SUBSELECT)
还是我可以进一步优化它?如果我想通过调用 findAll() 方法获取所有“As”怎么办?多个 children 的语法应该是什么?喜欢
"select a from A a join fetch a.b then ??"
列表< A > findAll()
Now, If I fetch A by id, I see a lot of queries get fired which turns out to be N+1 problem. To solve this, I added @Fetch(FetchMode.SUBSELECT) to all of the oneToMany relationships above which cause less queries to be fired.
您并不是说 how/when 这些查询已被触发,因此问题的可能原因是您从 HTTP 端点返回实体,然后将其序列化。使用 @Fetch(FetchMode.SUBSELECT)
是“提高”性能的一种方法,但只有在用于获取 A
的基本查询很简单的情况下才能很好地工作。如果它变得太复杂(分页、复杂谓词等),您应该坚持使用默认值 SELECT
,而是通过 @BatchSize( size = 32 )
注释配置适当的批处理大小。批处理大小的一个好的值是您希望返回的 A
个实例的数量,这样每个集合只执行一个查询。如果您允许最大页面大小为例如50,你设置成50就完美了
List< A > findAll()
如果您关心性能和可用性,请不要这样做。允许返回所有元素几乎没有意义,因为任何用户一次都不能处理超过 20 个元素。如前所述,始终对页面大小设置某种上限,以防止可能导致性能问题的误用。