2009-01-03 104 views
3

我正在使用Hibernate的JPA實現,並且由於爲獲取的每個實體發出了多個SQL查詢,因此性能很差。如果我使用加入的JPA查詢,它只會生成一個SQL查詢,但不會查找行將爲空的關係。JPA/Hibernate空值優化查詢優化

例如,考慮這個簡單的模式。一個人住在一個​​地址,並受僱於一家公司。地址和僱主都是可選的,因此可以爲空。

@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; 

我看到的問題是,在多個SQL查詢結果人單JPA查詢在數據庫上。例如,下面的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查詢與一羣聯接。問題是,如果地址或僱主爲空,則加入的查詢將無法找到它。

所以我離開時要麼使用慢速連接查詢,要麼快速連接的查詢不檢索行將爲空關係。我必須在這裏錯過一些東西。當然有一種快速和完整的查詢方法。

回答

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工作正常,這是JPA標準在很多方面的基礎。

它不與純連接一起工作的原因是默認是內連接。

+0

LEFT JOIN並獲得成功,謝謝。 – 2009-01-03 06:50:47

0

嘗試在地址和公司實體上設置批量大小(@BatchSize)。它不會將它們加載到一個連接中(這就是你之後的內容?),但是每次加載時都會加載它們。批量大小表示當它發現需要時應加載多少。

如果您的批量大小爲1(默認值),並加載10個人​​。然後遍歷它們,讀取它們的地址和公司條目,然後hibernate將爲10個人做一個查詢,然後每次需要這些人的地址或公司時,它將查詢該人的地址。

如果你已經在地址實體上設置了7的批量大小,那麼當你讀到第一個地址時,它會看到有超過7個當前代理的地址,並且會去找你7個地址。

如果您的地址和公司的BatchSize均爲7,並且您正在迭代10個人,那麼這將導致5個查詢,而不是目前的21個。仍然不是聯合會給你的1。然而,在你只需要Person對象而且不會觸及其中嵌入的地址/公司實體的情況下,聯接會比較慢(例如,您只想獲取人員ID列表,或者統計多少人是男/女)

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