使用JPA获取集合时,避免N + 1和笛卡尔积问题的标准方法是什么?

Joh*_*onn 3 java performance orm hibernate jpa

当一个实体的字段部分是集合时,人们希望以尽可能少的查询数并使用尽可能少的内存来获取数据。

第一个问题通过JPQL查询中的“联接获取”解决(解决了N + 1问题)。

但是,“ join fetch”(通过检查相应的SQL查询可以很容易地看到)引起笛卡尔乘积问题:对应于没有多重性的实体字段的每个“行”都以多重性N_1 x N_2 x ..出现在返回的结果集中。 x N_m,其中N_1是第一个集合的多重性,N_2是第二个集合的多重性,N_m是第m个集合的多重性,假定实体具有m个字段(即集合)。

Hibernate使用FetchMode.SUBSELECT解决了这个问题(如果我没记错的话,它会进行m + 1个查询,每个查询都不返回冗余数据)。解决JPA中此问题的标准方法是什么(在我看来,至少在这种情况下,我无法将JPA注释与Hibernate的注释混合使用)?

Vla*_*cea 5

该最安全的方式是使用查询替换集合,特别是当预期是尺寸足够大导致性能问题:

  1. 您删除了双向@OneToMany端,仅保留了拥有的@ManyToOne端

  2. 您选择父实体(例如,国家/地区),然后只需运行以下查询:

    select c from City c where c.country = :country
    select c from County c where c.country = :country
    select count(p), c.name from People p join p.country group by c.name
    
    Run Code Online (Sandbox Code Playgroud)

有关使用JPA和Hibernate映射集合的最佳方法的更多详细信息,请参阅本文。