Hibernate – 将ElementCollection与实体的其余部分联接起来进行查询

huangapple go评论69阅读模式
英文:

Hibernate - join ElementCollection with the rest of an entity fetch query

问题

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

这是实体部分:

@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; // <------- 我们关注这部分

    @ElementCollection
    @CollectionTable(name = "Websites", joinColumns = @JoinColumn(name = "myEntityId"))
    @Column(name = "websites")
    private List<String> websites; // <------- 我们关注这部分

    @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<MyEntity>来映射它,并调用myEntity.getPhones()时,我看到正在进行数据库调用,这就是导致减速的原因,在1000个实体上减速了70秒。
那么,我该如何强制它在首次调用findByTenantIdAndIdIn时执行join操作,就像调用时所做的那样?

注:

  • Phones是一个简单的表,具有列:[myEntityId, phone]
  • Websites也存在相同的问题。
英文:

I have major performance issues when I try to map an entity into a response.

This is the entity:

@Entity
@Table(name = &quot;MyEntity&quot;)
public class MyEntity extends BaseEntity {

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

    @ElementCollection
    @CollectionTable(name = &quot;Phones&quot;, joinColumns = @JoinColumn(name = &quot;myEntityId&quot;))
    @Column(name = &quot;phone&quot;)
    private List&lt;String&gt; phones; // &lt;------- we care about this

    @ElementCollection
    @CollectionTable(name = &quot;Websites&quot;, joinColumns = @JoinColumn(name = &quot;myEntityId&quot;))
    @Column(name = &quot;websites&quot;)
    private List&lt;String&gt; websites; // &lt;------- we care about this

    @Fetch(FetchMode.SUBSELECT)
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = &quot;myEntity&quot;)
    private List&lt;ContactEntity&gt; bbb;

    @Fetch(FetchMode.SUBSELECT)
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = &quot;myEntity&quot;)
    private List&lt;AddressEntity&gt; ccc;

}

This is how I use the DAL to fetch it:

List&lt;MyEntity&gt; findByTenantIdAndIdIn(String someOtherId, Set&lt;String&gt; MyEntityIds);

Now when I iterate over List&lt;MyEntity&gt; to map it, and call myEntity.getPhones(), I see that a DB call is being made, which is what causes the slowdown, a 70 seconds slowdown on 1000 entities.
So what can I do to force it to join in the first query it did when I called findByTenantIdAndIdIn?

Notes:

  • Phones is a simple table with columns: [myEntityId, phone]
  • The same problem happens with Websites

答案1

得分: 1

这与它是一个 @ElementCollection 无关。就像你已经找出的那样,你可以使用子选择抓取,或者还可以使用批量大小来进行选择抓取(默认策略)。另一种可能性是在查询中使用fetch join,但要小心在fetch join多个集合时,这可能会创建一个笛卡尔积,导致性能问题,因为传输的行数太多。一个fetch join示例HQL查询如下:

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

英文:

This has nothing to do with it being an @ElementCollection. Like you figured out, you can use subselect fetching or could also use a batch size for select fetching(the default strategy). Another possibility is to use a fetch join in the query, but be careful when fetch joining multiple collections as that might create a cartesian product which leads to a performance problem cause by too many rows being transfered. A fetch join example HQL query looks like this:

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

答案2

得分: 0

我发帖后立即解决了这个问题。

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

解决这个问题的另一种方法是不使用@ElementCollection,因为它性能较差,而是像他们在这个视频中推荐的那样,使用实体(Entity):https://thorben-janssen.com/hibernate-tips-query-elementcollection/。

英文:

I solved it right after I posted this.

I annotated phones and websites with @Fetch(FetchMode.SUBSELECT) which creates a parallel subquery.

Another way to solve this is simply to not use @ElementCollection because it has bad performance, use an Entity instead as they recommend in the video here: https://thorben-janssen.com/hibernate-tips-query-elementcollection/

huangapple
  • 本文由 发表于 2020年9月24日 00:11:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/64032102.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定