【问题标题】:Hibernate - join ElementCollection with the rest of an entity fetch queryHibernate - 将 ElementCollection 与实体获取查询的其余部分连接起来
【发布时间】:2020-09-23 16:11:40
【问题描述】:

当我尝试将实体映射到响应时,我遇到了严重的性能问题。

这是实体:

@Entity
@Table(name = "MyEntity")
public class MyEntity extends BaseEntity {

    @Column(name = "someOtherId", nullable = false)
    private String someOtherId;

    @ElementCollection
    @CollectionTable(name = "Phones", joinColumns = @JoinColumn(name = "myEntityId"))
    @Column(name = "phone")
    private List<String> phones; // <------- we care about this

    @ElementCollection
    @CollectionTable(name = "Websites", joinColumns = @JoinColumn(name = "myEntityId"))
    @Column(name = "websites")
    private List<String> websites; // <------- we care about this

    @Fetch(FetchMode.SUBSELECT)
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "myEntity")
    private List<ContactEntity> bbb;

    @Fetch(FetchMode.SUBSELECT)
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "myEntity")
    private List<AddressEntity> ccc;

}

这就是我使用 DAL 获取它的方式:

List<MyEntity> findByTenantIdAndIdIn(String someOtherId, Set<String> MyEntityIds);

现在,当我遍历 List&lt;MyEntity&gt; 来映射它并调用 myEntity.getPhones() 时,我看到正在进行数据库调用,这就是导致速度下降的原因,1000 个实体的速度下降了 70 秒。 那么当我调用findByTenantIdAndIdIn 时,我可以做些什么来强制它在第一个查询中使用join

注意事项:

  • Phones 是一个包含列的简单表:[myEntityId, phone]
  • Websites 也会出现同样的问题

【问题讨论】:

    标签: java spring-boot hibernate jpa


    【解决方案1】:

    这与 @ElementCollection 无关。就像您想的那样,您可以使用子选择获取,也可以使用批量大小进行选择获取(默认策略)。另一种可能性是在查询中使用 fetch join,但在 fetch join 多个集合时要小心,因为这可能会创建一个笛卡尔积,从而导致由于传输的行太多而导致性能问题。一个 fetch join 示例 HQL 查询如下所示:

    SELECT e FROM MyEntity e LEFT JOIN FETCH e.phones LEFT JOIN FETCH e.websites
    

    【讨论】:

    • 把它们变成实体而不是 ElementCollection 怎么样?
    • “怎么样”是什么意思?你能问一个更具体的问题吗?
    • 我的意思是把 PhonesWebsites 也改成实体,这样可以进一步提高性能吗?
    • 老实说,我不确定,但我怀疑@Fetch(SUBSELECT) 仅适用于实体。我认为这也适用于元素集合。
    • 使用像这样的 HQL 查询是唯一有助于强制 Hibernate 在 ElementCollection 上执行 JOIN 而不是 Subselect...谢谢
    【解决方案2】:

    我发布后立即解决了。

    我用 @Fetch(FetchMode.SUBSELECT) 注释电话和网站,这会创建一个并行子查询。

    解决此问题的另一种方法是不使用@ElementCollection,因为它性能不佳,而是使用他们在视频中推荐的实体:https://thorben-janssen.com/hibernate-tips-query-elementcollection/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-13
      • 2016-01-18
      • 1970-01-01
      • 2021-12-18
      • 1970-01-01
      • 2013-05-10
      • 1970-01-01
      • 2012-08-22
      相关资源
      最近更新 更多