【问题标题】:Does fetch all properties do left join under the hood?获取所有属性是否会在后台加入?
【发布时间】:2016-06-07 09:51:55
【问题描述】:

我的实体如下所示:为简化起见,我只显示了两个字段。我们决定一次性加载所有属性。

    @Entity     
    public class Person{
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Set<PhoneNumber> phoneNumbers = new HashSet<>(0);
     @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "AGENCY_ID")
        private Agency agency;

左连接:(这会返回重复记录。)

select person
from Person person left join person.agency ag left join person.phoneNumbers 
where upper(person.name) LIKE '%SU%' and upper(person.status.rcode)   = 'ACTIVE'
order by person.agency.name asc, person.id asc

left join with distinct : 这给出了“ORA-01791: not a SELECTed expression”,因为我在 order 子句中使用了机构字段。

select distinct person
    from Person person left join person.agency ag left join person.phoneNumbers 
    where upper(person.name) LIKE '%SU%' and upper(person.Status.rcode)   = 'ACTIVE'
    order by person.agency.name asc, person.id asc

left join fetch :这工作正常,没有重复。但对拉动 2000 人的记录有很大的影响。大约需要 15 秒,而仅左加入则需要 1 秒。

select  person
        from Person person left join fetch person.agency ag left join fetch person.phoneNumbers 
        where upper(person.name) LIKE '%SU%' and upper(person.Status.rcode)   = 'ACTIVE'
        order by person.agency.name asc, person.id asc

获取所有属性:没有重复。表现更好。但是.. 当我尝试像下面这样查询一个人时(此人没有任何代理):它返回人员记录(这意味着它正在执行左连接)。

 select person
    from Person person 
    fetch all properties
    where upper(person.name) LIKE '%SU%' and upper(person.status) = 'ACTIVE'
    order by  person.id asc

但是当我在下面做时,我没有取回这个人的记录。 (不同之处是按子句顺序添加了代理字段,在这种情况下似乎没有进行左连接。)

select person
from Person person 
fetch all properties
where upper(person.name) LIKE '%SU%' and upper(person.status) = 'ACTIVE'
order by person.agency.name asc, person.id asc

我正在寻找的是避免重复,可按表现良好的人的所有领域进行排序。

【问题讨论】:

  • JPA 中没有“获取所有属性”这样的语法。

标签: java hibernate hql


【解决方案1】:

导航路径语法 (person.agency) 总是被翻译成内部连接,这就是结果集中不包括没有代理的人的原因。

您必须显式编写外连接以避免隐式内连接:

select person
from Person person left outer join person.agency a
where upper(person.name) LIKE '%SU%' and upper(person.status) = 'ACTIVE'
order by a.name asc, person.id asc

编辑

left join 情况下的distinct 不起作用,因为按select distinct 子句中提到的列中未包含的列进行排序没有意义。

如果你想在查询中急切地加载惰性关联,那么你别无选择,只能做left join fetch。但也会返回重复项。要消除它们,只需将返回的列表添加到 LinkedHashSet 以保留返回的顺序:

List<Persons> result = new ArrayList(new LinkedHashSet(list))

关于这种方法的性能不佳,Hibernate 与它无关。您可能在左连接获取的实体中有一些急切加载的实体(因此遭受 n+1 选择问题),或者重复的实体非常大(因此生成和传输大型结果集)。

您可能希望使用@BatchSize 而不是left-join-fetching 集合以避免性能问题。

【讨论】:

  • 感谢巨龙博扎诺维奇。是的,我注意到当我在玩查询时,我们在这里进行 fetch all 的原因是为了获得正确的人数。当我只是“左加入”:此人中有 Set 时,如果电话号码集> 1,则查询返回重复的人。然后我们尝试了“left join fetch”,性能很差。所以我们转向“获取所有属性”,它表现良好,但在使用 person.agency in order by 子句时没有进行左连接。我正在尝试编写一个可以解决我所有问题的查询。
  • 这是我现在尝试的:“left join person.phoneNumber left join person.agency fetch all properties”这将返回重复记录。如果我只是获取所有属性,我看不到任何重复项。
  • @rohith 如果你加入一个集合,重复是很自然的。然后只需使用distinct 消除重复项:select distinct person from ...
  • 对不起,我忘了提到我遇到的不同问题。当我尝试按机构字段排序时,我得到“不是选定的表达式错误”。我的查询:“从 Person person left join person.agency ag 中选择不同的人 fetch all properties where upper(person.name) LIKE '%SU%' and upper(person.status) = 'ACTIVE' order by ag.name asc, person.id asc "
  • 我建议您在这种情况下忘记fetch all properties。没有它还能用吗?
猜你喜欢
  • 1970-01-01
  • 2020-07-14
  • 1970-01-01
  • 2019-08-22
  • 2013-04-05
  • 1970-01-01
  • 2017-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多