2015-10-23 133 views
1

我正在尋找優化休眠select查詢的最佳方式。休眠選擇查詢優化

這裏是一個基本的例子:

BDD模型 1個客戶端 - >ñ合同 - > N個選項

到請求客戶機 「XXXX」 的所有數據的最簡單的方式是這樣的:

final Query hqlQuery = jdbcTemplate.createHQLQuery("from Client cli left join fetch cli.contracts con left join fetch con.options where cli.id=:idClient"); 
hqlQuery .setString("idClient", "xxxx"); 

Client client = (Client) hqlQuery.uniqueResult(); 

有時這是不可能的,因爲有兩個數據要返回。

所以,我分裂的要求,somethink像:

// Query 1 
final Query hqlQueryClient = jdbcTemplate.createHQLQuery("from Client cli left join fetch cli.contracts where cli.id=:clientId"); 
hqlQueryClient.setString("clientId", "xxxx"); 

Client client = (Client) hqlQueryClient.uniqueResult(); 

List<String> listContractIds = new ArrayList<String>(); 

for (Contract contract : client.getContracts()) { 
    listContractIds.add(contract.getId()); 
} 

// Query 2 
final Query hqlQueryOptions = jdbcTemplate.createHQLQuery("from Option opt where opt.contract.id in(:contractIds)"); 
hqlQueryOptions.setParameterList("contractIds", listContractIds); 

List<Option> options = hqlQueryClient.list(); 

但是,與第二種方式,我不能在client對象「注入」 options,所以我必須處理clientoptions對象在我的代碼中,並在options列表中查找與我正在使用的合同對應的那些列表。

有沒有辦法用第二次請求的值來完成Hibernate對象(在我的例子中是客戶端)?

感謝您的幫助。

PS:請問如果現在還不清楚,我是法國人:)

回答

0

<rant> 我一般恨冬眠,因爲它是這樣一個浪費時間,也似乎運行數百個查詢時,你只運行如果少數寫SQL手動 <\rant>

如果強行使用Hibernate,我可能會使用類似3個查詢

  • from Options as o join fetch o.contract as co join fetch co.client as cl where cl = :client
  • from Contracts as co join fetch co.client as cl where cl = :client
  • from Client where clientId = :clientId

然後,我把他們都到適當Map<Long, List>地圖,做Java中的連接。

+0

沒有辦法直接在主對象中注入3個查詢的結果(而不是處理Map)? – pierrefevrier

+0

如果您只從選項 - >合同 - >客戶端導航,則您可能對第一個查詢正常。如果按照其他方式(客戶端 - >合同 - >選項),您將按[n + 1選擇](http://stackoverflow.com/questions/97197/what-is-the-n1-selects-issue)問題 –

+0

你說得對,但我無法從我的代碼中的Option - > Contract - > Client中導航,我正在以另一種方式(客戶端 - >合同 - >選項)進行導航。爲了避免n + 1選擇問題,我從來不會調用'contrat.getOptions()'。相反,我過濾結果的選項查詢以編程方式(通過contrat id),但它不像只調用'contrat.getOptions()',這是這篇文章的主題:我怎麼能做得更好:) – pierrefevrier

-2

使用Hibernate的好處是ORM。您可以將您的課程設置爲實體。所以你不必擔心簡單的查詢了。只需使用JPA即可完成該任務。該實體可以看起來像:

@Entity 
public class Client implements Serializable { 
    private Long id; 
    private ArrayList<Contract> contracts; 
    // more attributes here 
    @Id @GeneratedValue(strategy = GenerationType.AUTO) 
    public Long getId() { 
     return id; 
    } 

    @OneToMany 
    public ArrayList<Contract> getContracts() { 
     return contracts; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

    public void setContracts(ArrayList<Contract> contracts) { 
     this.contracts = contracts; 
    } 
} 

@Entity 
public class Contract implements Serializable { 
    private Long id; 
    private List<Option> options; 
    // more attributes here 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    public Long getId() { 
     return id; 
    } 

    @OneToMany 
    public List<Option> getOptions() { 
     return options; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

    public void setOptions(List<Option> options) { 
     this.options = options; 
    } 
} 

等等...

+1

嗨,你的迴應沒有上下文,我的問題不是關於映射,而是如何有效地查詢 – pierrefevrier

+0

從你想強制使用Hibernate編寫SQLQ的POV。由於你甚至不理解Hibernate是爲什麼而創建的,因此完全脫離了上下文。因此,玩得開心 – BuckRogers

0

第一:有多少數據你是否有結果的第一個查詢不起作用? 如果你的結果有很多行,而你想優化這個查詢,請檢查你從db獲得的所有數據是否真的需要。也許你應該對更扁平的其他物體進行投影。

如果您不用Java處理數據,只將它傳遞給前端考慮分頁結果。

+0

潛在1客戶 - > 50合同 - > 50選項 假設每個客戶,每個合同和每個選項都有20列,這意味着Hibernate必須處理50 * 20 * 50 * 20 = 1 000 000列。 – pierrefevrier

+0

你真的需要所有這些列嗎? –

+0

並非所有,但至少50%。 – pierrefevrier