我正在使用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查询带有一堆连接。问题是如果地址或雇主为空,则加入的查询将找不到它。
所以我要么使用慢连接的无连接查询,要么不检索行的快速连接查询将使空关系成为空。我必须在这里遗漏一些东西。当然,有一种快速完整的查询方式。
答案 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