2016-04-06 24 views
2

我是JPA/JPQL的新手,所以請原諒,如果這個問題不明確。用於檢索複雜實體的高效JPQL查詢

我正在嘗試查找高效的JQPL查詢以獲取複雜對象的所有記錄。

(即,由多個表來表示,與幾個一對多的關係 - 見以下簡化的例子):

class ComplexObject { 
    private Set< SubOject1> so1 ... 
    ..... 
    @OneToMany(fetch = FetchType.LAZY) 
    public Set< SubOject1>... 
} 

class SubObject1 { 
    private Set< SubOject2> so2 ... 
    ..... 
    @OneToMany(fetch = FetchType.LAZY) 
    public Set< SubOject2>... 
} 

我使用以下JPQL查詢:

select distinct CO 
from ComplexObject CO 
left join fetch CO.so1 SO1 
left join fetch SO1.so2 

的查詢在無狀態會話上運行,以便獲取DB中當前數據的實際快照,該數據與實體管理器分離(因此使用左連接提取)。

不幸的是,我遇到兩個問題:

  1. 由於複雜的對象包含SO1的多個實例,每個實例SO1 SO2包含的多個實例,底層轉換爲SQL查詢生成特定選擇查詢每行所有表連接的產品 - 非常浪費的解決方案。有沒有辦法減少內部選擇查詢的數量? (這看起來像可怕的N + 1查詢問題)。

  2. JPQL查詢返回所有表連接的產品上的每個內部SQL查詢的ComplexObject實例 - 這意味着對ComplexObject實例的多個引用。爲什麼這會發生在'select distinct'查詢上?

編輯:只是澄清 - 我使用的JPA框架是hibernate,而數據庫是HyperSQL。

編輯:(1)問題結果與使用p6spy日誌框架相關,p6spy日誌框架打印出大型數據庫表中的所有結果。記錄格式導致了許多查詢在哪裏執行的錯誤假設。

在嘗試微調性能時,使用本機查詢似乎沒有比使用JPQL查詢更好的性能。 使用本機查詢還會導致Object typed結果,這需要後處理。

+1

最有效的查詢是類型化的本地查詢。如果您不能忍受Hibernate(或其他ORM)開銷,那麼不要使用Criteria或JPQL查詢。 –

+0

@Baldurian:使用JPQL的一般概念是爲了在一個事務中獲取大部分數據庫數據有問題嗎? (即,在這種情況下應該使用原生查詢) –

+1

如果類型化原生查詢更有效,那麼標準或JPQL查詢的效率如何?大多數已命名查詢的處理都可以事先完成,並且根據查詢本身,無論是本機還是JPQL,都可以同樣高效或低效。原生查詢允許自定義,但大多數JPA提供商提供了一系列可以提高性能的選項,如果您知道自己在做什麼。 – Chris

回答

1

您可以使用View對象,你想要的東西只接收列:

StringBuilder sb = new StringBuilder(); 
sb.append(" SELECT new ").append(ObjectVO.class.getName()).append("(co.someInfo1, co.someInfo2, so1.someInfo)"); 
sb.append(" FROM ComplexObject co "); 
sb.append(" JOIN co.subOject1s so1 "); 
sb.append(" LEFT JOIN so1.so2 so2 "); 
sb.append(" WHERE so1.id = :idSo1 AND so2 = :someThing"); 

Query q = em.createQuery(sb.toString()); 
q.setParameter("idSo1", idSo1); 
q.setParameter("someThing", someThing); 

List<ObjectVO> listResult = q.getResultList(); 

的ObjectVO類:

public class ObjectVO { 

    private String info1; 
    private Long info2; 
    private String info3; 

    public PedidoModel(String info1, Long info2, String info3){ 
     this.info1 = info1; 
     this.info2 = info2; 
     this.info3 = info3; 
    } 

} 
+0

對於一些複雜的實體,我最終使用了類似的解決方案。 –