具有空值的JPA / Hibernate查询优化

时间:2009-01-03 01:48:29

标签: performance hibernate jpa java-ee hql

我正在使用Hibernate的JPA实现,并且由于为每个获取的实体发出了多个SQL查询,因此性能很差。如果我使用连接的JPA查询,它只生成一个SQL查询,但没有找到行将为null关系。

示例,请考虑这个简单的架构。一个人住在一个​​地址,并由一家公司雇用。地址和雇主都是可选的,因此可以为空。

@Entity
public  class Person {
    public name;

    @ManyToOne
    @Column(nullable=true)
    public Address address

    @ManyToOne
    @Column(nullable=true)
    public Company employer
}

@Entity
public  class Address {
    address attributes ...
}

@Entity
public  class Company {
    company attributes ...
}

上面没有显示每个JPA实体都有某种ID(密钥):

@Id
public Integer id;

我遇到的问题是Person上的单个JPA查询会导致数据库上出现多个SQL查询。例如,以下JPA查询:

select p from Person p where ...

导致SQL查询:

select ... from Person where ...

以及每个检索到的人的以下一对SQL查询:

select ... from Address a where a.id=xxx
select ... from Company c where c.id=yyy

这对性能产生巨大影响。如果查询结果集为1000人,则生成1 + 1000 + 1000 = 2001 SQL查询。

所以我尝试通过强制加入来优化JPA查询:

select p from Person p join p.address a join p.employer e where ...

或:

select p, a, e from Person p join p.address a join p.employer e where ...

这导致一个SQL查询带有一堆连接。问题是如果地址或雇主为空,则加入的查询将找不到它。

所以我要么使用慢连接的无连接查询,要么不检索行的快速连接查询将使空关系成为空。我必须在这里遗漏一些东西。当然,有一种快速完整的查询方式。

2 个答案:

答案 0 :(得分:3)

我的猜测是你需要一个左连接,即

SELECT p FROM Person p LEFT JOIN p.address a LEFT JOIN p.employer e WHERE...

请参阅this blog entry for an example

请注意,我实际上没有尝试使用JPA,但它在HQL中运行良好,HQL在很多方面都是JPA标准的基础。

它不使用普通连接的原因是默认是内连接。

答案 1 :(得分:0)

尝试在地址和公司实体上设置批量大小(@BatchSize)。它不会在连接中加载它们(你正在追求的是什么?),但每次加载它时它会加载一堆它们。 batchsize表示当发现它需要一个时它应加载多少。

如果批量大小为1(默认值),则加载10个人​​。然后迭代它们,读取它们的地址和公司项目,然后hibernate将对10个人进行一次查询,然后每次需要其中一个人的地址或公司时,它将查询该人的地址。

如果您在地址实体上设置了批量大小7,那么当您读取第一个地址时,它会看到当前有超过7个地址被代理,并且将获得7个地址。

如果您同时拥有BatchSize为7的地址和公司,并且您正在迭代10个人,那么这将导致5个查询,而不是当前获得的21个问题。仍然不是一个联合会给你的1。但是,在您只需要Person对象并且不会触及其中嵌入的Address / Company实体的情况下,连接会更慢(假设您只想获取人员ID的列表,或计算多少是男/女)

看看: http://hibernate.org/hib_docs/v3/reference/en/html/performance.html