3

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

例如,考虑这个简单的模式。一个人住在一个​​地址并受雇于一家公司。地址和雇主都是可选的,因此可以为空。

@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 查询。问题是如果地址或雇主为空,则连接查询将找不到它。

所以我要么使用慢的无连接查询,要么使用不检索行的快速连接查询将使关系为空。我一定在这里遗漏了一些东西。肯定有一种快速和完整查询的方法。

4

2 回答 2

3

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

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

有关示例,请参阅此博客条目

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

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

于 2009-01-03T02:44:54.320 回答
0

尝试在 Address 和 Company 实体上设置批处理大小 (@BatchSize)。它不会在连接中加载它们(这就是你所追求的吗?),但每次加载时它都会加载一堆。批量大小表示当它发现需要一个时应该加载多少。

如果您的批量大小为 1(默认值),并加载 10 个人。然后遍历他们,读取他们的地址和公司项目,然后 hibernate 将为这 10 个人进行一次查询,然后每次需要其中一个人的地址或公司时,它都会查询该人的地址。

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

如果您的 Address 和 Company 的 BatchSize 为 7,并且您正在迭代 10 个人,那么这将导致 5 个查询,而不是目前的 21 yo。仍然不是一个连接将给你的 1。但是,在您只想要 Person 对象并且不会触及嵌入其中的 Address/Company 实体的情况下(例如,您只想获取人员 id 的列表,或计算有多少是男/女)

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

于 2009-01-04T09:58:38.313 回答