这是一个N + 1问题,我该如何解决?

问题描述 投票:0回答:2

我有一个项目列表和一个客户列表。项目可以针对一个客户,每个客户都可以拥有多个项目。所以这是一个简单的1:n关系,其中项目是拥有方。

简化为必不可少的

@Entity
public class Project {
  @Id
  long id;

  @ManyToOne(optional = true)
  @JoinColumn(name = "customer", nullable = true, updatable = true)
  Customer customer;
}

@Entity
public class Customer {
  @Id
  long id;
}

当我加载项目列表时,我希望同时有效地检索客户。不是这种情况。对项目有一个单独的查询,然后为遇到的每个不同的客户发出单独的查询。

所以说我有100个项目分配给50个不同的客户。这将导致一个项目查询和50个客户查询。

这很快就会增加,对于大型项目/客户列表,我们的应用程序变得相当慢。这只是一个例子。我们所有具有关系的实体都会受到此行为的影响。

我已经在@Fetch(FetchMode.JOIN)字段上尝试了customers,如here所建议的那样,但它没有做任何事情,根据Hibernate,FetchMode.SUBQUERY不适用:

org.hibernate.AnnotationException:在ToOne关联上不允许使用FetchMode.SUBSELECT

我该如何解决这个问题?

java hibernate jpa query-performance
2个回答
1
投票

是的,这是n + 1选择问题的一本书的例子。

我在大多数情况下使用的方法是使关联变得懒惰并定义batch size

或者,您可以使用带有[left] join fetch的JPQL查询来直接从查询结果集初始化关联:

select p from Project p left join fetch p.customer

0
投票

是的,正如@ dragan-bozanovic所说,这是n + 1选择问题的一本书的例子。

在Spring-Boot 2.1.3中,@Fetch(FetchMode.JOIN)可用于解决它:

  @ManyToOne(optional = true)
  @Fetch(FetchMode.JOIN)
  @JoinColumn(name = "customer", nullable = true, updatable = true)
  Customer customer;

警告:如果关系可能无效,例如标记为@NotFound(action = NotFoundAction.IGNORE)时,每个无效关系将触发另一个SELECT查询。

© www.soinside.com 2019 - 2024. All rights reserved.